HomeGuidesRecipesAPI ExplorerForumSupport
Partner Portal
Partner Portal

Verifying bank accounts for ACH payments

Overview

According to Nacha rules, you must be authorized by the owner of an external bank account before you can process ACH debits from that bank account. Also, you must verify the validity and ownership of an external bank account upon its first use or upon changes to the account number.

This guide explains how Monite partners build the bank account verification UI.

📘

All API calls mentioned in this guide require a partner access token.

Building the bank account verification UI

Monite API requires the use of Plaid Link to verify US bank accounts. Plaid is an open banking solution that allows entity users to verify by securely entering their credentials in the Plaid Link modal. Plaid Link is a client-side component available via SDKs for all modern browsers and platforms, including web, iOS, Android, React Native, and mobile webviews.

You do not need a separate contract with Plaid. Monite API will generate Plaid access tokens for you that your application can use to initialize and display the Plaid Link modal. Monite will also customize the look & feel of the Plaid Link modal based on your branding needs.

Typical flow

Your application needs to display the Plaid Link modal at the appropriate step in your entity onboarding flow or bank account management interface.

The typical flow for bank account verification is:

  • During the entity onboarding flow, if the entity is US-based and wishes to use ACH payments, prompt the entity to verify its bank account.
  • If an entity chooses to verify its bank account, open the Plaid Link modal using the Plaid access token provided by Monite.
  • The following functionality is provided out of the box by the Plaid Link modal:
    • The user is prompted to select a bank and enter their bank account credentials.
      Note: Most US banks use OAuth for authentication, in which case Plaid Link will redirect the user to the bank's website for authentication instead.
    • Plaid Link displays a list of accounts from the selected bank.
    • The user selects the bank accounts they wish to verify and enable for ACH Direct Debit payments. The user can select any number of accounts or none.
    • After successful verification, Plaid redirects the user back to your application.
  • Monite gets the information about the verified bank account (such as the bank name and account number) from Plaid Link and compares it to the existing entity bank accounts. If the specified bank account does not exist in Monite yet, it is created automatically.
  • Monite sets the verification status of the specified bank account to set to verified.

From now on, the entity can make ACH payments from that bank account.

Before you begin

Before you start implementing bank account verifications in your application, contact us and provide the following information:

  • Redirect URL that should be used to return the users from Plaid Link back to your application. After a user successfully completes the OAuth flow via their bank's website or app, Plaid will redirect the user to this URL. This URL must be HTTPS and must not include query parameters. For more information, see Plaid's OAuth guide and the description of their redirect_uri parameter.
  • A list of required customizations for Plaid Link. Refer to Plaid documentation to learn about the available customizations. Note: the logo cannot be customized.

📘

You can use different customizations and redirect URL for the Sandbox and Production environments if needed.

We will provide you with a link_customization_name value that you will need to use when requesting Plaid Link access tokens from Monite API.

Use Plaid Link to verify a bank account

1. Get a Plaid Link token

Monite generates Plaid Link access tokens for our partners. To get a token, call POST /bank_accounts/start_verification with the following request body:

curl -X POST 'https://api.sandbox.monite.com/v1/bank_accounts/start_verification' \
     -H 'X-Monite-Version: 2024-01-31' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Authorization: Bearer YOUR_PARTNER_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
       "type": "airwallex_plaid",
       "airwallex_plaid": {
         "client_name": "Invoicing App",
         "link_customization_name": "My customization",
         "redirect_url": "https://example.com/oauth-page.html"
       }
     }'

The request body fields are:

  • type - Must be "airwallex_plaid".

  • client_name - Required. The name of your application or business to be displayed in Plaid Link. Up to 30 characters. If the name is longer than 30 characters, Plaid Link will display "This application" instead.

  • link_customization_name - Optional. The name of the Plaid Link customization provided to you by Monite. If omitted, the default customization will be used.

  • redirect_uri - Required. OAuth redirect URL that Plaid should use.

A successful 200 response looks like this:

{
  "type": "airwallex_plaid",
  "airwallex_plaid": {
    "client_name": "Invoicing App",
    "link_customization_name": "My customization",
    "redirect_url": "https://example.com/oauth-page.html",
    "link_token": "link-cd2d2e3d-f9a9-468c-bce4-4001f58778d2",
    "expires_at": "2023-10-03T11:25:39+0000"
  }
}

Note down the link_token value - you will need it on the next step.

2. Display Plaid Link

Next, your application needs to display Plaid Link. The way you can do this depends on the type of your application (such as React or iOS). For details, see Initializing Link in Plaid documentation.

Use the link_token value obtained on the previous step when initializing Plaid Link.

In the Plaid Link UI, an entity user needs to select their bank, authenticate in it, select a bank account to verify, and agree to the ACH debit authorization.

Use Plaid's onSuccess callback to capture the following information:

  • public_token
  • institution (id and name) - the bank that the user selected.
  • account (id, name, and mask) - the bank account that the user verified.

You will need these values for subsequent API calls to Monite.

Complete the verification

If an entity user successfully verifies the entity's bank account in Plaid, call Monite's POST /bank_accounts/complete_verification endpoint and provide the public_token and bank account information that you have obtained from Plaid. Additionally, provide the mandate object containing the name (signatory) and email address of the entity user who agrees to the ACH Direct Debit mandate on behalf of the entity. A PDF copy of the mandate will be sent to the specified email address.

curl -X POST 'https://api.sandbox.monite/com/v1/bank_accounts/complete_verification' \
     -H 'X-Monite-Verion: 2024-01-31' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'Content-Type: application/json' \
     -d '{
        "type": "airwallex_plaid",
        "airwallex_plaid": {
          "public_token": "public-sandbox-807f203f-0570-40e2-b728-97db915bfa09",
          "institution": {
            "id": "Wells Fargo",
            "name": "ins_1"
          },
          "account": {
            "id": "BxBXxLj1m4HMXBm9WZZmCWVbPjX16EHwv99vp",
            "name": "Main account",
            "mask": "0732"
          },
          "mandate": {
            "email": "[email protected]",
            "signatory": "Aisha Patton",
            "type": "us_ach_debit",
            "version": "1.0"
          }
        }
      }'

If the specified bank account does not already exist in the entity's data in Monite, it will be automatically added. In any case, the verification status of the bank account becomes "verified".

A successful 200 response returns the Monite ID of the bank account that was verified, along with its other details:

{
  "verifications": {
    "airwallex_plaid": {
      "status": "verified"
    }
  },
  "bank_account_id": "1c0d5f7e-8023-4235-b11f-e0e2b7f476e0",
  "iban": null,
  "bic": null,
  "bank_name": "Wells Fargo",
  "is_default_for_currency": false,
  "display_name": "string",
  "was_created_by_user_id": "31c5eafe-4bbc-49b5-a45c-41a73c27811b",
  "account_holder_name": "Aisha Patton",
  "account_number": "1234567890",
  "routing_number": "061000227",
  "sort_code": null,
  "currency": "USD",
  "country": "US"
}

Check the verification status of a bank account

🚧

Important

The /bank_accounts/{bank_account_id}/verifications endpoint returns the last known verification status and does not check the current verification status. Monite only learns the current verification status of a bank account when an entity attempts to make an ACH batch payment from that account.

To check the verification status of an entity's bank account, call GET /bank_accounts/{bank_account_id}/verifications:

curl -X GET 'https://api.sandbox.monite.com/v1/bank_accounts/1c0d5...6e0/verifications' \
  -H 'X-Monite-Version: 2024-01-31' \
  -H 'X-Monite-Entity-ID: ENTITY_ID' \
  -H 'Authorization: Bearer YOUR_PARTNER_TOKEN'

In the response, examine the value of the airwallex_plaid.status field:

{
  "airwallex_plaid": {
    "status": "verified"
  }
}

The possible status values are:

  • verified - The ownership of this bank account is verified.
  • expired - This status usually means that the entity has changed its bank login credentials or explicitly revoked access to this bank account. The verification can also expire naturally after a long period of time (typically over a year). The entity can refresh the verification if needed. A successful verification changes the status back to verified.
  • suspended - The verification becomes suspended if the entity disputes an outgoing ACH payment after it had settled.

The following image illustrates possible transitions between the verification statuses:

Bank account verification statuses

Refresh an expired verification

If the verification of an entity bank account has expired, it is possible to refresh the verification. Start by calling POST /bank_accounts/{bank_accoun_id}/refresh_verification. The request body is the same as you use when requesting a Plaid Link token from Monite:

curl -X POST 'https://api.sandbox.monite.com/v1/bank_accounts/1c0d5...6e0/start_verification' \
     -H 'X-Monite-Version: 2024-01-31' \
     -H 'X-Monite-Entity-Id: ENTITY_ID' \
     -H 'content-type: application/json' \
     -d '{
       "type": "airwallex_plaid",
       "airwallex_plaid": {
         "client_name": "Invoicing App",
         "link_customization_name": "My customization",
         "redirect_url": "https://example.com/oauth-page.html"
       }
     }'

A successful 200 response contains the Plaid Link token link_token:

{
  "type": "airwallex_plaid",
  "airwallex_plaid": {
    "client_name": "Invoicing App",
    "link_customization_name": "My customization",
    "redirect_url": "https://example.com/oauth-page.html",
    "link_token": "link-cd2d2e3d-f9a9-468c-bce4-4001f58778d2",
    "expires_at": "2023-10-03T11:25:39+0000"
  }
}

Use this token to initialize and display Plaid Link where the user can refresh the verification. See the Display Plaid Link section above.