> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tesouro.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Linking an external bank account

> Connect, initiate micro-ACH deposits, validate the amounts — the three-call sequence that gets an external bank account from UNVERIFIED to VERIFIED.

Linking an external bank account is a three-call sequence for most callers. You connect the account with its routing and account number, you initiate the two micro-ACH deposits, then the user submits the amounts back to validate them. Each call returns the same `ExternalBankAccountResponse` with an updated `verificationStatus`. Trusted callers can collapse this to a single connect call — see [Manual verification](#manual-verification-trusted-callers) below.

## 1. Connect the external bank account

```http lines theme={null}
POST /embedded-banking/v1/external-bank-accounts
```

```json title="Request" lines theme={null}
{
  "nickname": "Operating account",
  "accountNumber": "000123456789",
  "routingNumber": "021000021",
  "type": "CHECKING",
  "nameOnAccount": "Northfield Software LLC"
}
```

```json title="Response (201 Created)" lines theme={null}
{
  "id": "ea_0a8c3f4d1b2e4d7a9c5b2e8f6a1d3c4b",
  "accountNumber": "***6789",
  "routingNumber": "021000021",
  "nickname": "Operating account",
  "type": "CHECKING",
  "verificationStatus": "UNVERIFIED",
  "accountStatus": "ACTIVE",
  "nameOnAccount": "Northfield Software LLC"
}
```

`type` is `CHECKING` or `SAVINGS`. The response's `accountNumber` is masked from this point on — capture the `id` to address the external bank account in later calls. The connection is recorded but no money has moved yet; `verificationStatus` is `UNVERIFIED`.

## 2. Initiate micro-deposit verification

```http lines theme={null}
POST /embedded-banking/v1/external-bank-accounts/{id}/link
```

This call takes no body. Tesouro sends two small ACH credits to the connected account and flips `verificationStatus` to `VERIFICATION_SENT` on the response. The credits land within standard ACH timing — typically one to two business days, depending on the receiving bank.

```json title="Response (200 OK)" lines theme={null}
{
  "id": "ea_0a8c3f4d1b2e4d7a9c5b2e8f6a1d3c4b",
  "verificationStatus": "VERIFICATION_SENT",
  ...
}
```

## 3. Validate the deposit amounts

The user checks their outside bank, finds the two Tesouro credits, and submits the amounts. Both are passed in minor units (cents).

```http lines theme={null}
POST /embedded-banking/v1/external-bank-accounts/{id}/validate
```

```json title="Request" lines theme={null}
{
  "firstAmount": 12,
  "secondAmount": 34
}
```

If both amounts match, `verificationStatus` flips to `VERIFIED` and the external bank account is immediately usable as a counterparty in [ACH transfers](/embedded-banking/guides/money-movement/ach). If they don't match, the call returns a `400` and the external bank account stays in `VERIFICATION_SENT` for the user to retry. After enough failures the service moves it to `FAILED`; see [Troubleshooting](/embedded-banking/guides/bank-accounts/troubleshooting).

Most integrations let users drive this themselves through the [linked accounts component](/embedded-banking/guides/embedded-components/linked-accounts) instead of building the UI from scratch. The endpoints above are what the component calls under the hood — use them directly when you need a custom flow or a fully white-label experience.

## Verification statuses

| Status              | Meaning                                                                                                                                                                                                      |
| :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `UNVERIFIED`        | External bank account is connected but micro-deposits haven't been initiated yet. Call `/link` to send them.                                                                                                 |
| `VERIFICATION_SENT` | Micro-deposits are out; waiting on the user to submit amounts via `/validate`. The external bank account can't yet be a transfer counterparty.                                                               |
| `VERIFIED`          | Amounts matched. The external bank account is usable on the ACH rail until it's marked failed or its `accountStatus` changes.                                                                                |
| `FAILED`            | The micro-deposits were returned by the receiving bank, the user exhausted their validation attempts, or another upstream failure occurred. A failed external bank account is read-only — connect a new one. |

## Manual verification (trusted callers)

Some callers already have an out-of-band way of confirming control over the external bank account and don't need Tesouro's micro-deposit round trip — typically a platform sitting higher in the hierarchy that has already verified the underlying account with its own business customers. Those callers can pass a `verification` block on the connect call and the external bank account is created with `verificationStatus: VERIFIED` immediately. No `/link` or `/validate` calls are needed.

```http lines theme={null}
POST /embedded-banking/v1/external-bank-accounts
```

```json title="Request" lines theme={null}
{
  "nickname": "Operating account",
  "accountNumber": "000123456789",
  "routingNumber": "021000021",
  "type": "CHECKING",
  "nameOnAccount": "Northfield Software LLC",
  "verification": {
    "method": "MANUAL"
  }
}
```

The response comes back with `verificationStatus: VERIFIED` straight away. The record retains the verification method (`MANUAL`) and a timestamp so the bypass is auditable.

This path is gated by the `embedded:externalbankaccount:set-verification` scope, and the calling organization must have accepted the relevant disclosures. Callers without the scope that send a `verification` block get back a `403`. `verification.method: "MICRO_DEPOSIT"` is rejected at connect time on every caller — that's what the three-call flow above is for. If your integration needs the manual path, the scope has to be granted by Tesouro; the default is the micro-deposit flow.
