Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/src/App.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ $threads-font-path: "~plaid-threads/fonts";
flex-direction: column;
align-items: center;
min-width: 70 * $unit;
max-width: 84 * $unit;
max-width: 120 * $unit;
margin: 0 auto;
}
16 changes: 15 additions & 1 deletion frontend/src/Components/ProductTypes/Products.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
incomePaystubsCategories,
transferCategories,
transferAuthorizationCategories,
signalCategories,
transformAuthData,
transformTransactionsData,
transformBalanceData,
Expand All @@ -28,6 +29,7 @@ import {
transformTransferData,
transformTransferAuthorizationData,
transformIncomePaystubsData,
transformSignalData,
} from "../../dataUtilities";

const Products = () => {
Expand Down Expand Up @@ -142,11 +144,23 @@ const Products = () => {
name="Transfer"
categories={transferCategories}
schema="/transfer/create/"
description="(After calling /transfer/authorization/create) Execute an authorized 1-dollar ACH transfer payment from the linked account"
description="(After calling /transfer/authorization/create) Execute an authorized 1-dollar ACH transfer payment from the first linked account"
transformData={transformTransferData}
/>
</>
)}
{products.includes("signal") && (
<>
<Endpoint
endpoint="signal_evaluate"
name="Signal"
categories={signalCategories}
schema="/signal/evaluate"
description="Evaluate the return risk of a proposed $100 debit from the first linked account (in Sandbox, results are randomly generated)"
transformData={transformSignalData}
/>
</>
)}
{products.includes("income_verification") && (
<Endpoint
endpoint="/income/verification/paystubs"
Expand Down
53 changes: 51 additions & 2 deletions frontend/src/dataUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
TransferCreateResponse,
TransferAuthorizationCreateResponse,
IncomeVerificationPaystubsGetResponse,
SignalEvaluateResponse,
Paystub,
Earnings,
} from "plaid/dist/api";
Expand Down Expand Up @@ -109,13 +110,22 @@ interface TransferDataItem {
network: string;
}


interface TransferAuthorizationDataItem {
authorizationId: string;
authorizationDecision: string;
decisionRationaleCode: string | null;
decisionRationaleDescription: string | null;
}

interface SignalDataItem {
customerInitiatedReturnRiskScore: number | undefined | null;
customerInitiatedReturnRiskTier: number | undefined | null;
bankInitiatedReturnRiskScore: number | undefined | null;
bankInitiatedReturnRiskTier: number | undefined | null;
daysSinceFirstPlaidConnection: number | undefined | null;
}

interface IncomePaystubsDataItem {
description: string;
currentAmount: number | null;
Expand Down Expand Up @@ -144,7 +154,8 @@ export type DataItem =
| AssetsDataItem
| TransferDataItem
| TransferAuthorizationDataItem
| IncomePaystubsDataItem;
| IncomePaystubsDataItem
| SignalDataItem;

export type Data = Array<DataItem>;

Expand Down Expand Up @@ -399,6 +410,31 @@ export const transferAuthorizationCategories: Array<Categories> = [
},
];

export const signalCategories: Array<Categories> = [
{
title: "Customer-initiated return risk score",
field: "customerInitiatedReturnRiskScore"
},

{
title: "Customer-initiated return risk tier",
field: "customerInitiatedReturnRiskTier"
},
{
title: "Bank-initiated return risk score",
field: "bankInitiatedReturnRiskScore"
},
{
title: "Bank-initiated return risk tier",
field: "bankInitiatedReturnRiskTier"
},
{
title: "Sample core attribute: Days since first Plaid connection",
field: "daysSinceFirstPlaidConnection"
},
];



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

export const transformTransferAuthorizationData = (data: TransferAuthorizationCreateResponse) => {
export const transformSignalData = (data: SignalEvaluateResponse) => {
return [
{
customerInitiatedReturnRiskTier: data.scores.customer_initiated_return_risk!.risk_tier,
customerInitiatedReturnRiskScore: data.scores.customer_initiated_return_risk!.score,
bankInitiatedReturnRiskTier: data.scores.bank_initiated_return_risk!.risk_tier,
bankInitiatedReturnRiskScore: data.scores.bank_initiated_return_risk!.score,
daysSinceFirstPlaidConnection: data.core_attributes!.days_since_first_plaid_connection,
},
];
};


export const transformTransferAuthorizationData = (data: TransferAuthorizationCreateResponse): Array<DataItem> => {
const transferAuthorizationData = data.authorization;
return [
{
Expand Down
30 changes: 30 additions & 0 deletions go/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func main() {
r.GET("/api/assets", assets)
r.GET("/api/transfer_authorize", transferAuthorize)
r.GET("/api/transfer_create", transferCreate)
r.GET("/api/signal_evaluate", signalEvaluate)

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

func signalEvaluate(c *gin.Context) {
ctx := context.Background()
accountsGetResp, _, err := client.PlaidApi.AccountsGet(ctx).AccountsGetRequest(
*plaid.NewAccountsGetRequest(accessToken),
).Execute()

if err != nil {
renderError(c, err)
return
}

accountID = accountsGetResp.GetAccounts()[0].AccountId

signalEvaluateRequest := plaid.NewSignalEvaluateRequest(
accessToken,
accountID,
"txn1234",
100.00)

signalEvaluateResp, _, err := client.PlaidApi.SignalEvaluate(ctx).SignalEvaluateRequest(*signalEvaluateRequest).Execute()

if err != nil {
renderError(c, err)
return
}

c.JSON(http.StatusOK, signalEvaluateResp)
}

func investmentTransactions(c *gin.Context) {
ctx := context.Background()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.plaid.quickstart.resources.LinkTokenWithPaymentResource;
import com.plaid.quickstart.resources.PaymentInitiationResource;
import com.plaid.quickstart.resources.PublicTokenResource;
import com.plaid.quickstart.resources.SignalResource;
import com.plaid.quickstart.resources.TransactionsResource;
import com.plaid.quickstart.resources.TransferAuthorizeResource;
import com.plaid.quickstart.resources.TransferCreateResource;
Expand Down Expand Up @@ -114,6 +115,7 @@ public void run(final QuickstartConfiguration configuration,
environment.jersey().register(new LinkTokenWithPaymentResource(plaidClient, plaidProducts, countryCodes, redirectUri));
environment.jersey().register(new PaymentInitiationResource(plaidClient));
environment.jersey().register(new PublicTokenResource(plaidClient));
environment.jersey().register(new SignalResource(plaidClient));
environment.jersey().register(new TransactionsResource(plaidClient));
environment.jersey().register(new TransferAuthorizeResource(plaidClient));
environment.jersey().register(new TransferCreateResource(plaidClient));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.plaid.quickstart.resources;

import java.io.IOException;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.plaid.client.request.PlaidApi;
import com.plaid.client.model.AccountsGetRequest;
import com.plaid.client.model.AccountsGetResponse;
import com.plaid.client.model.AccountIdentity;
import com.plaid.client.model.SignalEvaluateRequest;
import com.plaid.client.model.SignalEvaluateResponse;
import com.plaid.quickstart.QuickstartApplication;

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import retrofit2.Response;

@Path("/signal_evaluate")
@Produces(MediaType.APPLICATION_JSON)
public class SignalResource {
private final PlaidApi plaidClient;

public SignalResource(PlaidApi plaidClient) {
this.plaidClient = plaidClient;
}

@GET
public SignalEvaluateResponse signalEvaluate() throws IOException {
AccountsGetRequest accountsGetRequest = new AccountsGetRequest()
.accessToken(QuickstartApplication.accessToken);

Response<AccountsGetResponse> accountsGetResponse = plaidClient
.accountsGet(accountsGetRequest)
.execute();

QuickstartApplication.accountId = accountsGetResponse.body().getAccounts().get(0).getAccountId();

SignalEvaluateRequest signalEvaluateRequest = new SignalEvaluateRequest()
.accessToken(QuickstartApplication.accessToken)
.accountId(QuickstartApplication.accountId)
.clientTransactionId("txn1234")
.amount(100.00);

Response<SignalEvaluateResponse> signalEvaluateResponse = plaidClient
.signalEvaluate(signalEvaluateRequest)
.execute();

return signalEvaluateResponse.body();

}
}
20 changes: 20 additions & 0 deletions node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -575,3 +575,23 @@ app.get('/api/transfer_create', function (request, response, next) {
})
.catch(next);
});

app.get('/api/signal_evaluate', function (request, response, next) {
Promise.resolve()
.then(async function () {
const accountsResponse = await client.accountsGet({
access_token: ACCESS_TOKEN,
});
ACCOUNT_ID = accountsResponse.data.accounts[0].account_id;

const signalEvaluateResponse = await client.signalEvaluate({
access_token: ACCESS_TOKEN,
account_id: ACCOUNT_ID,
client_transaction_id: 'txn1234',
amount: 100.00,
});
prettyPrintResponse(signalEvaluateResponse);
response.json(signalEvaluateResponse.data);
})
.catch(next);
});
21 changes: 21 additions & 0 deletions python/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from plaid.model.ach_class import ACHClass
from plaid.model.transfer_create_idempotency_key import TransferCreateIdempotencyKey
from plaid.model.transfer_user_address_in_request import TransferUserAddressInRequest
from plaid.model.signal_evaluate_request import SignalEvaluateRequest
from plaid.api import plaid_api

load_dotenv()
Expand Down Expand Up @@ -532,6 +533,26 @@ def transfer():
error_response = format_error(e)
return jsonify(error_response)

@app.route('/api/signal_evaluate', methods=['GET'])
def signal():
global account_id
request = AccountsGetRequest(access_token=access_token)
response = client.accounts_get(request)
account_id = response['accounts'][0]['account_id']
try:
request = SignalEvaluateRequest(
access_token=access_token,
account_id=account_id,
client_transaction_id='txn1234',
amount=100.00)
response = client.signal_evaluate(request)
pretty_print_response(response.to_dict())
return jsonify(response.to_dict())
except plaid.ApiException as e:
error_response = format_error(e)
return jsonify(error_response)


# This functionality is only relevant for the UK Payment Initiation product.
# Retrieve Payment for a specified Payment ID

Expand Down
27 changes: 27 additions & 0 deletions ruby/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,33 @@
end
end

get '/api/signal_evaluate' do
begin
# We call /accounts/get to obtain first account_id - in production,
# account_id's should be persisted in a data store and retrieved
# from there.
accounts_get_request = Plaid::AccountsGetRequest.new({ access_token: access_token })
accounts_get_response = client.accounts_get(accounts_get_request)
account_id = accounts_get_response.accounts[0].account_id

signal_evaluate_request = Plaid::SignalEvaluateRequest.new({
access_token: access_token,
account_id: account_id,
client_transaction_id: 'tx1234',
amount: 100.00
})
signal_evaluate_response = client.signal_evaluate(signal_evaluate_request)
pretty_print_response(signal_evaluate_response.to_hash)
content_type :json
signal_evaluate_response.to_hash.to_json
rescue Plaid::ApiError => e
error_response = format_error(e)
pretty_print_response(error_response)
content_type :json
error_response.to_json
end
end

get '/api/transfer_create' do
begin
transfer_create_request = Plaid::TransferCreateRequest.new({
Expand Down