Skip to content

Commit b5bd2e6

Browse files
authored
Merge pull request plaid#463 from plaid/adh-add-signal-to-quickstart
Adh add signal to quickstart
2 parents 25e87cd + fd4f88c commit b5bd2e6

File tree

9 files changed

+222
-4
lines changed

9 files changed

+222
-4
lines changed

frontend/src/App.module.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ $threads-font-path: "~plaid-threads/fonts";
1111
flex-direction: column;
1212
align-items: center;
1313
min-width: 70 * $unit;
14-
max-width: 84 * $unit;
14+
max-width: 120 * $unit;
1515
margin: 0 auto;
1616
}

frontend/src/Components/ProductTypes/Products.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
incomePaystubsCategories,
1717
transferCategories,
1818
transferAuthorizationCategories,
19+
signalCategories,
1920
transformAuthData,
2021
transformTransactionsData,
2122
transformBalanceData,
@@ -28,6 +29,7 @@ import {
2829
transformTransferData,
2930
transformTransferAuthorizationData,
3031
transformIncomePaystubsData,
32+
transformSignalData,
3133
} from "../../dataUtilities";
3234

3335
const Products = () => {
@@ -142,11 +144,23 @@ const Products = () => {
142144
name="Transfer"
143145
categories={transferCategories}
144146
schema="/transfer/create/"
145-
description="(After calling /transfer/authorization/create) Execute an authorized 1-dollar ACH transfer payment from the linked account"
147+
description="(After calling /transfer/authorization/create) Execute an authorized 1-dollar ACH transfer payment from the first linked account"
146148
transformData={transformTransferData}
147149
/>
148150
</>
149151
)}
152+
{products.includes("signal") && (
153+
<>
154+
<Endpoint
155+
endpoint="signal_evaluate"
156+
name="Signal"
157+
categories={signalCategories}
158+
schema="/signal/evaluate"
159+
description="Evaluate the return risk of a proposed $100 debit from the first linked account (in Sandbox, results are randomly generated)"
160+
transformData={transformSignalData}
161+
/>
162+
</>
163+
)}
150164
{products.includes("income_verification") && (
151165
<Endpoint
152166
endpoint="/income/verification/paystubs"

frontend/src/dataUtilities.ts

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
TransferCreateResponse,
1515
TransferAuthorizationCreateResponse,
1616
IncomeVerificationPaystubsGetResponse,
17+
SignalEvaluateResponse,
1718
Paystub,
1819
Earnings,
1920
} from "plaid/dist/api";
@@ -109,13 +110,22 @@ interface TransferDataItem {
109110
network: string;
110111
}
111112

113+
112114
interface TransferAuthorizationDataItem {
113115
authorizationId: string;
114116
authorizationDecision: string;
115117
decisionRationaleCode: string | null;
116118
decisionRationaleDescription: string | null;
117119
}
118120

121+
interface SignalDataItem {
122+
customerInitiatedReturnRiskScore: number | undefined | null;
123+
customerInitiatedReturnRiskTier: number | undefined | null;
124+
bankInitiatedReturnRiskScore: number | undefined | null;
125+
bankInitiatedReturnRiskTier: number | undefined | null;
126+
daysSinceFirstPlaidConnection: number | undefined | null;
127+
}
128+
119129
interface IncomePaystubsDataItem {
120130
description: string;
121131
currentAmount: number | null;
@@ -144,7 +154,8 @@ export type DataItem =
144154
| AssetsDataItem
145155
| TransferDataItem
146156
| TransferAuthorizationDataItem
147-
| IncomePaystubsDataItem;
157+
| IncomePaystubsDataItem
158+
| SignalDataItem;
148159

149160
export type Data = Array<DataItem>;
150161

@@ -399,6 +410,31 @@ export const transferAuthorizationCategories: Array<Categories> = [
399410
},
400411
];
401412

413+
export const signalCategories: Array<Categories> = [
414+
{
415+
title: "Customer-initiated return risk score",
416+
field: "customerInitiatedReturnRiskScore"
417+
},
418+
419+
{
420+
title: "Customer-initiated return risk tier",
421+
field: "customerInitiatedReturnRiskTier"
422+
},
423+
{
424+
title: "Bank-initiated return risk score",
425+
field: "bankInitiatedReturnRiskScore"
426+
},
427+
{
428+
title: "Bank-initiated return risk tier",
429+
field: "bankInitiatedReturnRiskTier"
430+
},
431+
{
432+
title: "Sample core attribute: Days since first Plaid connection",
433+
field: "daysSinceFirstPlaidConnection"
434+
},
435+
];
436+
437+
402438

403439
export const incomePaystubsCategories: Array<Categories> = [
404440
{
@@ -619,7 +655,20 @@ export const transformLiabilitiesData = (data: LiabilitiesDataResponse) => {
619655
return credit!.concat(mortgages!).concat(student!);
620656
};
621657

622-
export const transformTransferAuthorizationData = (data: TransferAuthorizationCreateResponse) => {
658+
export const transformSignalData = (data: SignalEvaluateResponse) => {
659+
return [
660+
{
661+
customerInitiatedReturnRiskTier: data.scores.customer_initiated_return_risk!.risk_tier,
662+
customerInitiatedReturnRiskScore: data.scores.customer_initiated_return_risk!.score,
663+
bankInitiatedReturnRiskTier: data.scores.bank_initiated_return_risk!.risk_tier,
664+
bankInitiatedReturnRiskScore: data.scores.bank_initiated_return_risk!.score,
665+
daysSinceFirstPlaidConnection: data.core_attributes!.days_since_first_plaid_connection,
666+
},
667+
];
668+
};
669+
670+
671+
export const transformTransferAuthorizationData = (data: TransferAuthorizationCreateResponse): Array<DataItem> => {
623672
const transferAuthorizationData = data.authorization;
624673
return [
625674
{

go/server.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ func main() {
115115
r.GET("/api/assets", assets)
116116
r.GET("/api/transfer_authorize", transferAuthorize)
117117
r.GET("/api/transfer_create", transferCreate)
118+
r.GET("/api/signal_evaluate", signalEvaluate)
118119

119120
err := r.Run(":" + APP_PORT)
120121
if err != nil {
@@ -449,6 +450,35 @@ func transferCreate(c *gin.Context) {
449450
c.JSON(http.StatusOK, transferCreateResp)
450451
}
451452

453+
func signalEvaluate(c *gin.Context) {
454+
ctx := context.Background()
455+
accountsGetResp, _, err := client.PlaidApi.AccountsGet(ctx).AccountsGetRequest(
456+
*plaid.NewAccountsGetRequest(accessToken),
457+
).Execute()
458+
459+
if err != nil {
460+
renderError(c, err)
461+
return
462+
}
463+
464+
accountID = accountsGetResp.GetAccounts()[0].AccountId
465+
466+
signalEvaluateRequest := plaid.NewSignalEvaluateRequest(
467+
accessToken,
468+
accountID,
469+
"txn1234",
470+
100.00)
471+
472+
signalEvaluateResp, _, err := client.PlaidApi.SignalEvaluate(ctx).SignalEvaluateRequest(*signalEvaluateRequest).Execute()
473+
474+
if err != nil {
475+
renderError(c, err)
476+
return
477+
}
478+
479+
c.JSON(http.StatusOK, signalEvaluateResp)
480+
}
481+
452482
func investmentTransactions(c *gin.Context) {
453483
ctx := context.Background()
454484

java/src/main/java/com/plaid/quickstart/QuickstartApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.plaid.quickstart.resources.LinkTokenWithPaymentResource;
1818
import com.plaid.quickstart.resources.PaymentInitiationResource;
1919
import com.plaid.quickstart.resources.PublicTokenResource;
20+
import com.plaid.quickstart.resources.SignalResource;
2021
import com.plaid.quickstart.resources.TransactionsResource;
2122
import com.plaid.quickstart.resources.TransferAuthorizeResource;
2223
import com.plaid.quickstart.resources.TransferCreateResource;
@@ -114,6 +115,7 @@ public void run(final QuickstartConfiguration configuration,
114115
environment.jersey().register(new LinkTokenWithPaymentResource(plaidClient, plaidProducts, countryCodes, redirectUri));
115116
environment.jersey().register(new PaymentInitiationResource(plaidClient));
116117
environment.jersey().register(new PublicTokenResource(plaidClient));
118+
environment.jersey().register(new SignalResource(plaidClient));
117119
environment.jersey().register(new TransactionsResource(plaidClient));
118120
environment.jersey().register(new TransferAuthorizeResource(plaidClient));
119121
environment.jersey().register(new TransferCreateResource(plaidClient));
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.plaid.quickstart.resources;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import com.plaid.client.request.PlaidApi;
7+
import com.plaid.client.model.AccountsGetRequest;
8+
import com.plaid.client.model.AccountsGetResponse;
9+
import com.plaid.client.model.AccountIdentity;
10+
import com.plaid.client.model.SignalEvaluateRequest;
11+
import com.plaid.client.model.SignalEvaluateResponse;
12+
import com.plaid.quickstart.QuickstartApplication;
13+
14+
import java.util.List;
15+
import javax.ws.rs.GET;
16+
import javax.ws.rs.Path;
17+
import javax.ws.rs.Produces;
18+
import javax.ws.rs.core.MediaType;
19+
20+
import retrofit2.Response;
21+
22+
@Path("/signal_evaluate")
23+
@Produces(MediaType.APPLICATION_JSON)
24+
public class SignalResource {
25+
private final PlaidApi plaidClient;
26+
27+
public SignalResource(PlaidApi plaidClient) {
28+
this.plaidClient = plaidClient;
29+
}
30+
31+
@GET
32+
public SignalEvaluateResponse signalEvaluate() throws IOException {
33+
AccountsGetRequest accountsGetRequest = new AccountsGetRequest()
34+
.accessToken(QuickstartApplication.accessToken);
35+
36+
Response<AccountsGetResponse> accountsGetResponse = plaidClient
37+
.accountsGet(accountsGetRequest)
38+
.execute();
39+
40+
QuickstartApplication.accountId = accountsGetResponse.body().getAccounts().get(0).getAccountId();
41+
42+
SignalEvaluateRequest signalEvaluateRequest = new SignalEvaluateRequest()
43+
.accessToken(QuickstartApplication.accessToken)
44+
.accountId(QuickstartApplication.accountId)
45+
.clientTransactionId("txn1234")
46+
.amount(100.00);
47+
48+
Response<SignalEvaluateResponse> signalEvaluateResponse = plaidClient
49+
.signalEvaluate(signalEvaluateRequest)
50+
.execute();
51+
52+
return signalEvaluateResponse.body();
53+
54+
}
55+
}

node/index.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,23 @@ app.get('/api/transfer_create', function (request, response, next) {
575575
})
576576
.catch(next);
577577
});
578+
579+
app.get('/api/signal_evaluate', function (request, response, next) {
580+
Promise.resolve()
581+
.then(async function () {
582+
const accountsResponse = await client.accountsGet({
583+
access_token: ACCESS_TOKEN,
584+
});
585+
ACCOUNT_ID = accountsResponse.data.accounts[0].account_id;
586+
587+
const signalEvaluateResponse = await client.signalEvaluate({
588+
access_token: ACCESS_TOKEN,
589+
account_id: ACCOUNT_ID,
590+
client_transaction_id: 'txn1234',
591+
amount: 100.00,
592+
});
593+
prettyPrintResponse(signalEvaluateResponse);
594+
response.json(signalEvaluateResponse.data);
595+
})
596+
.catch(next);
597+
});

python/server.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from plaid.model.ach_class import ACHClass
4747
from plaid.model.transfer_create_idempotency_key import TransferCreateIdempotencyKey
4848
from plaid.model.transfer_user_address_in_request import TransferUserAddressInRequest
49+
from plaid.model.signal_evaluate_request import SignalEvaluateRequest
4950
from plaid.api import plaid_api
5051

5152
load_dotenv()
@@ -532,6 +533,26 @@ def transfer():
532533
error_response = format_error(e)
533534
return jsonify(error_response)
534535

536+
@app.route('/api/signal_evaluate', methods=['GET'])
537+
def signal():
538+
global account_id
539+
request = AccountsGetRequest(access_token=access_token)
540+
response = client.accounts_get(request)
541+
account_id = response['accounts'][0]['account_id']
542+
try:
543+
request = SignalEvaluateRequest(
544+
access_token=access_token,
545+
account_id=account_id,
546+
client_transaction_id='txn1234',
547+
amount=100.00)
548+
response = client.signal_evaluate(request)
549+
pretty_print_response(response.to_dict())
550+
return jsonify(response.to_dict())
551+
except plaid.ApiException as e:
552+
error_response = format_error(e)
553+
return jsonify(error_response)
554+
555+
535556
# This functionality is only relevant for the UK Payment Initiation product.
536557
# Retrieve Payment for a specified Payment ID
537558

ruby/app.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,33 @@
370370
end
371371
end
372372

373+
get '/api/signal_evaluate' do
374+
begin
375+
# We call /accounts/get to obtain first account_id - in production,
376+
# account_id's should be persisted in a data store and retrieved
377+
# from there.
378+
accounts_get_request = Plaid::AccountsGetRequest.new({ access_token: access_token })
379+
accounts_get_response = client.accounts_get(accounts_get_request)
380+
account_id = accounts_get_response.accounts[0].account_id
381+
382+
signal_evaluate_request = Plaid::SignalEvaluateRequest.new({
383+
access_token: access_token,
384+
account_id: account_id,
385+
client_transaction_id: 'tx1234',
386+
amount: 100.00
387+
})
388+
signal_evaluate_response = client.signal_evaluate(signal_evaluate_request)
389+
pretty_print_response(signal_evaluate_response.to_hash)
390+
content_type :json
391+
signal_evaluate_response.to_hash.to_json
392+
rescue Plaid::ApiError => e
393+
error_response = format_error(e)
394+
pretty_print_response(error_response)
395+
content_type :json
396+
error_response.to_json
397+
end
398+
end
399+
373400
get '/api/transfer_create' do
374401
begin
375402
transfer_create_request = Plaid::TransferCreateRequest.new({

0 commit comments

Comments
 (0)