Plaid logo
Docs
ALL DOCS

Transfer (beta)

  • Introduction to Transfer and Transfer UI
  • Payment Profiles
  • Sending or receiving funds
  • Sweeping funds
  • Guarantee
  • Reconciling transfers
  • Recurring transfers
  • Transfers in the Dashboard
  • ACH requirements
  • Transfers using Transfer UI
  • Transfer webhooks
  • Add transfer to your app
Plaid logo
Docs
Plaid.com
Get API keys
Open nav

Guarantee

Learn how Plaid guarantees ACH transactions

API Reference

View Transfer requests, responses, and example code

View Transfer API

Quickstart

Learn about Plaid's key concepts and run starter code

Get started

Guarantee is currently in closed beta and approval is required to participate. If you're interested in learning more or participating in the beta program, contact Sales or, for existing customers, your Account Manager.

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

Overview

Guarantee is an optional feature in Plaid Transfer. With Guarantee, Plaid analyzes proposed transfers and guarantees a subset of them. If a Plaid-guaranteed transfer is returned, Plaid will cover the cost of the ACH return and the funds will never leave your bank account.

Guarantee also enables faster fund availability. Once Plaid guarantees a transfer, the funds will be included in the next sweep, even if the transfer is not yet settled. Additionally, there is no holding period for guaranteed debit transfers.

Guarantee is backwards compatible with existing Transfer integrations – no changes are necessary to use it. Information about transfer guarantees is provided in the response payloads of the /transfer/authorization/create and /transfer/create endpoints.

In order to qualify for a guaranteed transfer, the following fields are required when calling /transfer/authorization/create : idempotency_key, user.phone_number (optional if email_address provided), user.email_address (optional if phone_number provided), device.ip_address, device.user_agent, and user_present.

Using a beacon

Plaid’s beacon collects non-intrusive data that helps our models combat fraudulent transactions. Improved detection helps increase your guarantee coverage and control your return rates. This process occurs behind the scenes and does not impact page load time for consumers. Plaid requires a beacon to be implemented for Guarantee customers who are not using Transfer UI and have a web checkout experience.

Installing a beacon on your webpage

The beacon script for web can be found at https://cdn.plaid.com/beacon/stable/beacon.js and exposes runPlaidBeacon, which can be used to run it and retrieve a beacon_session_id. For best results, we recommend loading and running the beacon script upon checkout page load.

Select Language
Copy
1// beacon.ts
2declare global {
3 interface Window {
4 runPlaidBeacon: () => Promise<{ beacon_session_id: string }>;
5 }
6}
7
8let beaconLoaded: Promise<
9 () => Promise<{ beacon_session_id: string }>
10> | null = null;
11
12const beacon = async function(): Promise<{ beacon_session_id: string }> {
13 if (beaconLoaded == null) {
14 beaconLoaded = new Promise(resolve => {
15 const script = document.createElement('script');
16 script.type = 'text/javascript';
17 script.async = true;
18 script.src = 'https://cdn.plaid.com/beacon/stable/beacon.js';
19 script.onload = async () => {
20 resolve(window.runPlaidBeacon);
21 };
22 document.head.appendChild(script);
23 });
24 }
25 return beaconLoaded.then(async runPlaidBeacon => {
26 return await runPlaidBeacon();
27 });
28};
29
30// Returns an Object with beacon_session_id set
31beacon();

The beacon_session_id is cached by runPlaidBeacon so if you prefer not to store it, you can re-call beacon at a later point, which will either retrieve the cached value or will re-run the script and return a fresh beacon_session_id if the cached one has expired.

Including beacon_session_id on Transfer API requests

The beacon_session_id will need to be threaded through to the place where you make the API call to Plaid (specifically the /transfer/authorization/create endpoint) and included on the request body.

Select Language
Copy
1const request: TransferAuthorizationCreateRequest = {
2 access_token: 'access-sandbox-71e02f71-0960-4a27-abd2-5631e04f2175',
3 account_id: '3gE5gnRzNyfXpBK5wEEKcymJ5albGVUqg77gr',
4 type: 'credit',
5 network: 'ach',
6 amount: '12.34',
7 ach_class: 'ppd',
8 user: {
9 legal_name: 'Anne Charleston',
10 },
11 beacon_session_id: '97150461-72b3-4779-9a54-6982488ed436',
12};
13
14try {
15 const response = await client.transferAuthorizationCreate(request);
16 const authorizationId = response.data.authorization.id;
17} catch (error) {
18 // handle error
19}

Guarantees and sweeps

Guarantees

When /transfer/authorization/create is called, Plaid performs a risk assessment on the proposed transfer and determines whether the transfer can be guaranteed. The response will contain information about the guarantee.

Copy
1{
2 "authorization": {
3 "id": "c685bd6e-108e-4c61-834a-2548a0ff2176",
4 "created": "2020-08-06T17:27:15Z",
5 "decision": "approved",
6 "decision_rationale": null,
7 "guarantee_decision": "NOT_GUARANTEED",
8 "guarantee_decision_rationale": {
9 "code": "RETURN_BANK",
10 "description": "..."
11 },
12 "proposed_transfer": { ... },
13 },
14 "idempotency_key": "74e0b11e-28a5-11ed-a261-0242ac120002",
15 "request_id": "saKrIBuEB9qJZno"
16}

If the transfer is guaranteed, the guarantee_decision decision field in the response will be "GUARANTEED" and the guarantee_decision_rationale field will be null. If the transfer is not guaranteed, the guarantee_decision field will be "NOT_GUARANTEED" and the guarantee_decision_rationale object will include more information about why the transfer could not be guaranteed. This information is also returned in the response payload of /transfer/create when the transfer is created.

Sweeps

Once Plaid receives a transfer creation request that's been guaranteed, the amount of that transfer is then included in the next sweep. At a later time, if that guaranteed transfer is returned, Plaid does not reverse-sweep the fund and the sweep_status of the transfer remains as swept.

For example, you collect a total of $3000 debits from users, of which $500 is guaranteed. On the same day (let’s say before the ACH cutoff window on that day), a $500 sweep is originated. The next day Plaid receives a $100 guaranteed return and a $200 non-guaranteed return. If you have 1 day hold on debits, the net-sum of the sweep on this day would be $2300. In total, you receive $2800. You are only responsible for the $200 return which is not guaranteed.

Simulating Guarantees in Sandbox

In the Sandbox environment, all transfer amounts less than or equal to $20 will be guaranteed, while amounts over $20 will not be guaranteed, allowing you to test both guaranteed and non-guaranteed transfers.

Sample Sandbox scenarios
  1. Create 4 transfers using /transfer/authorization/create and /transfer/create for $5, $10, $20, and $40. All but the $40 transaction will be guaranteed.

  2. Simulate a "posted" event for all transfers by calling the /sandbox/transfer/simulate.

  3. Simulate a sweep by calling /sandbox/transfer/sweep/simulate. Confirm the $75 sweep amount using /transfer/sweep/list and /transfer/event/list. Inspect each transfer with /transfer/get and confirm that sweep_status is "swept".

  4. Simulate a "returned" event for the $10, $20, and $40 transfers by calling /sandbox/transfer/simulate.

  5. Simulate a sweep by calling /sandbox/transfer/sweep/simulate. Confirm the sweep amount is -$40. Inspect that only the $40 transfer’s sweep_status is "return_swept". In this scenario, the $10 and $20 transfers were guaranteed and are not deducted. The $5 transfer is not deducted as it was not returned, and the returned $40 transfer is deducted as it was not guaranteed.

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