Plaid logo
Docs
ALL DOCS

Transfer (beta)

  • Introduction to Transfer and Transfer UI
  • Sending or receiving funds
  • Sweeping funds
  • Guarantee
  • Reconciling transfers
  • ACH processing windows and timelines
  • ACH returns
  • ACH authorization
  • Transfers using Transfer UI
  • Transfer webhooks
  • Add transfer to your app
Plaid logo
Docs
Plaid.com
Get API keys
Open nav

Sending and Receiving Funds

Learn how to send or receive funds

Transfer is only supported in Plaid's Sandbox and Production environments.

Prerequisites
  • Integrate Plaid’s front-end library, Plaid Link, to authenticate user bank accounts and create Items.

  • Create a Link token using /link/token/create with the parameter products set to ['transfer'], then initialize Link with this token. Ensure that you initialize Link with only the transfer product. Ensure also that you have an access token and associated Items in a good state.

  • If an Item is not in a good state (i.e., you receive decision: "approved" and decision_rationale.code: "USER_LOGIN_REQUIRED" when calling /transfer/authorization/create), use Link in Update Mode to re-authenticate your user and retry the authorization. You can still create a transfer in this state, but it's best practice and in your best interest to only process transfers when an Item is in a good state (i.e., you receive decision: "approved" and decision_rationale: null when calling /transfer/authorization/create) to minimize the risk of an ACH return.

  • The access_token must be associated with a depository checking or savings account.

Determine the transfer failure risk

To determine the transfer failure risk, call the /transfer/authorization/create endpoint with the following:

  • The user's access_token and the account_id that represents the account where you'd like to send funds to

  • The amount (fund amount) you’re sending

  • type as credit if sending funds, or type as debit if receiving funds

  • ach_class as ppd for an personal account, or as ccd for a business account

  • user object with legal_name and other information (if you've specified ccd as the ach_class, you'll also need to specify the business’s name on the account within the user.legal_name parameter; if set to a person’s name it will be rejected).

Select Language
Copy
1const request: TransferAuthorizationCreateRequest = {
2 access_token: 'ACCESS_TOKEN',
3 account_id: '3gE5gnRzNyfXpBK5wEEKcymJ5albGVUqg77gr',
4 type: 'credit',
5 network: 'ach',
6 amount: '12.34',
7 ach_class: 'ppd',
8 user: {
9 legal_name: 'Anna Charleston',
10 },
11};
12
13try {
14 const response = await client.transferAuthorizationCreate(request);
15 const authorizationId = response.data.authorization.id;
16} catch (error) {
17 // handle error
18}

The response will contain an authorization object with details about the transfer authorization, including:

  • authorization.id, you'll need this to create the transfer in next step (this expires after 24 hours so you should persist this in a datastore)

  • authorization.decision, the decision from the authorization engine regarding the transfer. If this decision is "approved", you can proceed to the next step and create the transfer. If the decision is "declined", you will not be able to create the transfer (for more information on the decision and decision_rationale fields, see Transfer decision authorization).

Copy
1{
2 "authorization": {
3 "id": "460cbe92-2dcc-8eae-5ad6-b37d0ec90fd9",
4 "created": "2020-08-06T17:27:15Z",
5 "decision": "approved",
6 "decision_rationale": null,
7 "proposed_transfer": {
8 "ach_class": "ppd",
9 "account_id": "3gE5gnRzNyfXpBK5wEEKcymJ5albGVUqg77gr",
10 "type": "credit",
11 "user": {
12 "legal_name": "Anna Charleston",
13 "phone_number": "510-555-0128",
14 "email_address": "acharleston@email.com",
15 "address": {
16 "street": "100 Market Street",
17 "city": "San Francisco",
18 "region": "California",
19 "postal_code": "94103",
20 "country": "US"
21 }
22 },
23 "amount": "12.34",
24 "network": "ach",
25 "origination_account_id": "0123-4567-8901-2345-67890123"
26 }
27 },
28 "request_id": "saKrIBuEB9qJZno"
29}
Create the transfer

Create the transfer by calling the /transfer/create endpoint with the following:

  • The authorization_id of the transfer (returned from the previous step)

  • The unique authorization_id you must generate (for more information, see Transfer authorization id)

  • user’s access_token and account_id you want funds to be sent to

  • amount you’re sending

  • type as credit (i.e., a push payment)

  • network (either same-day-ach or ach)

  • ach_class (either ppd for an personal account or ccd for a business account)

  • user object with legal_name and other information (if you've specified ccd as the ach_class, you'll also need to specify the business’s name on the account within the user.legal_name parameter; if set to a person’s name it will be rejected).

Many of these parameters are the same as those specified when determining the transfer failure risk. This is in case you'd like to process an amount different from the amount that was authorized (only for amounts less than the original). For example, you may initially authorize for $100, but may only need to charge the user $90.

Select Language
Copy
1const request: TransferCreateRequest = {
2 type: 'credit',
3 network: 'ach',
4 amount: '12.34',
5 description: 'payment',
6 ach_class: 'ppd',
7 user: {
8 legal_name: 'Anna Charleston',
9 },
10 access_token: accessToken,
11 account_id: '3gE5gnRzNyfXpBK5wEEKcymJ5albGVUqg77gr',
12 authorization_id: '231h012308h3101z21909sw',
13};
14try {
15 const response = await client.transferCreate(request);
16 const transfer = response.data.transfer;
17} catch (error) {
18 // handle error
19}

In the response is a transfer object. We recommend persisting the transfer.id in a datastore as you’ll need this when reconciling transactions or canceling a transaction.

Copy
1{
2 "transfer": {
3 "id": "460cbe92-2dcc-8eae-5ad6-b37d0ec90fd9",
4 "ach_class": "ppd",
5 "account_id": "3gE5gnRzNyfXpBK5wEEKcymJ5albGVUqg77gr",
6 "type": "credit",
7 "user": {
8 "legal_name": "Anna Charleston",
9 "phone_number": "510-555-0128",
10 "email_address": "acharleston@email.com",
11 "address": {
12 "street": "100 Market Street",
13 "city": "San Francisco",
14 "region": "California",
15 "postal_code": "94103",
16 "country": "US"
17 }
18 },
19 "amount": "12.34",
20 "description": "A description of the transfer",
21 "created": "2020-08-06T17:27:15Z",
22 "status": "pending",
23 "network": "ach",
24 "cancellable": true,
25 "failure_reason": null,
26 "metadata": {
27 "key1": "value1",
28 "key2": "value2"
29 },
30 "origination_account_id": "0123-4567-8901-2345-67890123"
31 },
32 "request_id": "saKrIBuEB9qJZno"
33}

Sample app code

For a real-life example of an app that incorporates the /transfer/authorization/create and /transfer/create endpoints, see the Node-based Plaid Pattern Transfer sample app. Pattern Transfer is a sample subscriptions payment app that enables ACH bank transfers. The Transfer create code can be found in transfers.js

Was this helpful?
Developer community
GitHub
GitHub
Stack Overflow
Stack Overflow
YouTube
YouTube
Twitter
Twitter