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

# Recipients

> Who gets paid — why the payout rail decides everything, how verification actually works, and why there is no update

A recipient is a saved set of payout instructions: who the money goes to, over
which rail, in which currency. You create one, it gets verified, and from then on
you reference it by id when you submit a transfer.

**The payout rail is the single most important field on a recipient.** It decides
which provider onboards them, which verification the *customer* needs, which
fields are mandatory, and whether the recipient is usable immediately or has to
clear a check first. Almost every surprise on this surface traces back to it.

> [!NOTE]
>
> This is the conceptual guide. For the endpoints themselves — parameters,
> schemas and worked bodies — see the
> [Recipients API reference](https://docs.endl.io/api-reference/recipients/add-recipient.md).

## The rail decides who verifies the customer

Adding a recipient is gated on the customer's verification — but on **the
verification belonging to the provider that onboards that rail**, not on one
global KYC flag.

| `payoutRail` | Onboarded by | Customer must have completed |
| - | - | - |
| `AED_LOCAL` | Lorum | Lorum onboarding |
| `CRYPTO` | — (no counterparty) | Sumsub KYC |
| Paywho-settled rails — `BANK_TRANSFER`, `ALIPAY`, `CHINA_UNIONPAY_CARD_TRANSFERS`, `HUMO_UZCARD`, `CASH_PICKUP`, … | Paywho | Sumsub KYC |
| `SWIFT` | Keyrails | Keyrails onboarding |
| Everything else — `ACH`, `FEDWIRE`, `SEPA`, `FPS`, `CHAPS`, … | Bridge | Bridge KYC |

> [!WARNING]
>
> **A customer who can add one recipient may be refused on another.** This is the
> gate working, not a bug. A Bridge restriction blocks Bridge-backed rails and
> nothing else — it must not stop an `AED_LOCAL` recipient that Lorum has already
> verified, a `SWIFT` recipient Keyrails has verified, or a `CRYPTO` recipient that
> touches no fiat account at all.
>
> `SWIFT` is settled by **Keyrails**, not Bridge, and creates no Bridge
> counterparty — so it asks for Keyrails onboarding. This is the same verification
> [Generate quote](https://docs.endl.io/api-reference/quotes/generate-quote.md) already requires before it
> will price a SWIFT transfer, so a recipient you can add is one you can pay.
>
> Reading, listing and deleting a recipient need only **Sumsub** KYC, whatever
> the rail.

## Required fields are not fixed

There is no single schema that satisfies every recipient. What you must send
depends on the currency and the rail together.

**1. Ask what this corridor needs**

[Get recipient fields](https://docs.endl.io/api-reference/reference/get-recipient-fields.md) answers for a specific country, currency, rail and recipient type, and returns each field’s validation rules and options. Drive your form from it rather than hardcoding a shape.

Pass `recipientType` while you are still creating the recipient.

**2. Map each field to the request body**

Get recipient fields names each field by a catalogue key. Most keys are also the
request field; the ones below are not, and a key sent as-is at the top level is
ignored without an error.

| Get recipient fields `key` | Send it as |
| - | - |
| `bankId` | `providerBankId` (top level) |
| `governmentIdNumber` | `governmentId` |
| `bankSwiftCode` | `swiftBic` |
| `bankAccountType` | `bankType` |
| `addressLine1`, `city`, `state`, `postalCode`, `region` | `recipientAddress.<same name>` |
| `country` | `recipientAddress.countryThreeLetter` |
| `bankCity`, `bankState` | `institutionalAddress.city`, `institutionalAddress.state` |
| `nativeAddress` | `nativeAddress` (top level) |
| every other key | the same name, top level |

Each field in the Get recipient fields response also carries `requestPath`, the
exact place to send it.

**3. Send the seven that are always required**

Whatever the corridor, these are validated on every add:

| Field | Notes |
| - | - |
| `type` | `BUSINESS` or `INDIVIDUAL`. |
| `currency` | ISO 4217 — what the recipient is paid in. |
| `currencySymbol` | The symbol for that currency. |
| `currencyId` | Endl's numeric id, from [List currencies](https://docs.endl.io/api-reference/reference/list-currencies.md). |
| `payoutRail` | The rail. |
| `relationshipToCustomer` | How the recipient relates to the customer — `SUPPLIER`, `EMPLOYEE`, `SELF`, `SPOUSE`, `SUBSIDIARY_COMPANY`, and others. |
| the name | `firstName` + `lastName` for `INDIVIDUAL`, `businessName` for `BUSINESS`. |

**4. Add the rail-specific coordinates**

`ifsc` for Indian rails, `swiftBic` for SWIFT, `iban` for SEPA, `sortCode`
for UK, `bankRoutingNumber` for US, `walletAddress` + `walletChain` for
`CRYPTO`.

A **US bank** recipient (`bankType: "us"`) must also carry `accountType`,
which has to be `checking` or `savings`.

For Paywho bank transfers, `providerBankId`: the `code` of the chosen option on
the `bankId` field. For GBP, `bankBranchCode` is filled from `sortCode` when you
leave it out.

**5. Send the country as an id, in two places**

Send `countryId` — Endl's numeric id, from
[List countries](https://docs.endl.io/api-reference/reference/list-countries.md) — both at the top
level and inside `recipientAddress`, alongside the address lines
(`addressLine1`, `addressLine2`, `city`, `state`, `region`, `postalCode` and
`country`).

| Where | What it does |
| - | - |
| Top level | Narrows the payout-rail check to that country — without it, the check accepts any country's rails. On the standard endpoint it also fills in a missing `countryTwoLetter` / `countryThreeLetter`, and is then required for every rail except AED and `CRYPTO`. **Not saved.** |
| `recipientAddress.countryId` | **Saved** on the recipient and returned on it. Not sent → saved as `null`. |

Send both `recipientAddress.countryTwoLetter` and `countryThreeLetter` and they
are used as sent. Leave out either and it is filled from the top-level
`countryId`; a code you did send is kept.

On **POBO**, also send `recipientAddress.countryTwoLetter` and
`countryThreeLetter`; POBO does not derive them.

`institutionalAddress` is the receiving bank's address, with exactly the same
fields. It is required for GBP, with a valid UK postcode, and is used as the
beneficiary bank address on AED payouts.

> [!NOTE]
>
> Send `countryId` in two places. Inside `recipientAddress` it is saved on the
> recipient. At the top level it is used to check the payout rail and, if you leave
> out `recipientAddress.countryTwoLetter` or `countryThreeLetter`, to fill them in;
> it is not saved.

## Verification: immediate for some rails, asynchronous for others

Whether a new recipient is usable straight away depends — again — on the rail.

> **Active immediately**
>
> `CRYPTO`, `AED_LOCAL`, `SWIFT` and the Paywho-settled rails create **no Bridge
> counterparty**. The recipient is saved and marked `ACTIVE` in the same call.
> You can pay to it at once.

> **Verified asynchronously**
>
> Bridge-backed fiat rails register an external account with Bridge **after**
> the response is sent. The recipient exists immediately, but its counterparty
> status settles later.

For the second group, poll
[Get counterparty checks](https://docs.endl.io/api-reference/recipients/get-counterparty-checks.md). It
reads the recipient's provider-side state with no side effects, and reports
`status`, `counterpartyId`, `addedToAccountsProvider` and `statusUpdatedOn`.

Statuses you may see: `OPEN`, `ACTIVE`, `CLOSED`, `FROZEN`, `PENDING`, `EDD`,
`DORMANT`, and the `_L2F` variants. **Treat the set as open** and compare
case-insensitively — only `ACTIVE` means "ready".

> [!NOTE]
>
> **There are no recipient webhooks.** Nothing is emitted when a recipient is
> created, verified, or deleted. Polling Get counterparty checks is the only way
> to learn that a Bridge-backed recipient has cleared.

### India, IMPS and the penny drop

An **India customer** adding an `IMPS` + `INR` recipient whose
`relationshipToCustomer` is `SELF` triggers a **penny-drop verification** — a
tiny real transfer used to confirm the account exists. It happens inside the add
call: it succeeds and the recipient comes back `ACTIVE`, or it fails and the add
fails with the provider's reason.

> [!WARNING]
>
> **Any other INR recipient is refused.** `IMPS` + `INR` that is not an India
> customer's own `SELF` account returns `400 INR recipients not supported`. INR
> payout recipients are not generally available on this surface today.

## There is no update

**Recipient update was withdrawn from the v0 API.** There is no `PUT` or `PATCH`
on either the recipients surface or the POBO one.

To change a recipient's details, **add a new recipient and delete the old one.**
Transfers already submitted against the old recipient are unaffected — they
carry their own copy of the payout details.

> [!NOTE]
>
> This is deliberate: payout instructions that have been verified by a provider
> should not mutate underneath transactions that referenced them. A new set of
> details is a new recipient, with its own verification.

## Deleting

Delete is a **soft delete**. The recipient is marked deleted, stops appearing in
listings, and can no longer be referenced — then the external account is removed
at the provider asynchronously.

The response is `200` with a confirmation message, not a recipient object:

```json Delete recipient — 200 theme={null}
{ "message": "DeleteRecipient success!" }
```

Deleting a recipient that does not exist, belongs to another customer, or
is already deleted returns `404`.

> [!NOTE]
>
> Several recipients can share one provider-side external account. Deleting one
> of them leaves the shared account in place for the others — Endl only tears the
> external account down when the last recipient using it goes.

## Listing

[List recipients](https://docs.endl.io/api-reference/recipients/list-recipients.md) is a **`POST`**, not
a `GET` — the filter set is a body, not a query string. `size` defaults to `0`, and
`size: 0` returns every recipient rather than none.

Beyond paging (`page`, `size`, `sortBy` — `createdOn,desc` is recommended) you can
filter on `recipientType` (`INDIVIDUAL`, `BUSINESS`), `paymentType`
(`BANK_ACCOUNT`, `CRYPTO_WALLET`), `currency` (exact, case-insensitive) and `search`
(a substring of first name, last name, currency, email or bank name). Other filter
fields are accepted but ignored today.

Each item is the full [recipient object](https://docs.endl.io/api-reference/recipients/list-recipients.md).
Keys with no value are left out, except inside the two address objects, and
`alias` is never returned.

## Things that will refuse a recipient

Beyond field validation and the KYC gate, six business rules reject an add:

| Refusal | Why |
| - | - |
| **Duplicate account** | The same payout details already exist for this customer. Matched on IBAN for IBAN currencies, on SWIFT BIC + account number for SWIFT, and on account number + IFSC for Indian rails. |
| **Duplicate external account** | `409` — an ACH/Fedwire recipient with the same account and routing number already exists. |
| **Duplicate Paywho account** | `400 Account exists` — a recipient on a Paywho-settled rail (such as `BANK_TRANSFER`) with the same account number already exists. |
| **SWIFT not enabled** | SWIFT must be switched on for the customer. Being a business is not sufficient. |
| **Corridor exclusivity** | Once a customer has sent in `INR`, `PKR` recipients are refused, and vice versa. One corridor per customer. |
| **India compliance restriction** | Customers with a PK/BD nexus are blocked from INR and SWIFT-to-India recipients. |

## Scoping and reference ids

Every recipients path is `/{userId}/…`, and both ids in a path are **reference
ids, not UUIDs**.

| You send | Shape | Wrong shape | Well-formed but unknown |
| - | - | - | - |
| `{userId}` | `cus_…` | `404` | `404` |
| `{recipientId}` | `rec_…` | `400` | `404` |

A customer id that doesn't resolve — malformed, unknown, deleted or another partner's — is always `404 ERRREF_1001`, field `userId`.

A recipient that is deleted or belongs to a different customer is reported as
`404 ERRREC_1000` — `Recipient '{recipientId}' not found` — never `403`. The answer is
the same on [Get recipient](https://docs.endl.io/api-reference/recipients/get-recipient.md),
[Delete recipient](https://docs.endl.io/api-reference/recipients/delete-recipient.md) and
[Get counterparty checks](https://docs.endl.io/api-reference/recipients/get-counterparty-checks.md), so
recipient ids cannot be probed across customers.

A customer that belongs to **another partner** is reported the same way as one that
does not exist: `404 ERRREF_1001`, `User with ID '{id}' not found`.

## Error handling

`ERRREC_1000` (`404`) is the only recipient-domain code: the recipient is deleted or
does not belong to this customer. Everything else uses the shared
envelope and the `ERRCORE_` codes in
[Errors and the response envelope](https://docs.endl.io/api-reference/errors.md).

Validation and business refusals come back as `400` with the reason in
`errors[0]`, written to be shown to a user. **Branch on `errors[0].code`, never
on the message text.**

| You get | Do this |
| - | - |
| `400` | Fix the input, or the customer's verification. Never retry unchanged. |
| `403` | The key lacks `recipients`, or the customer has not completed the verification this rail needs. |
| `404` | The customer or recipient does not exist under this partner. |
| `409` | A recipient with these account details already exists. |
| `429` | Back off. The window is one minute. |

## Common pitfalls

> **400 on add, and the message names a field I did not send**
>
> Unknown keys at the top level are ignored, so a misspelled field reads as a
> missing one. Inside `recipientAddress` and `institutionalAddress` an unknown key
> is rejected with `400 Invalid value for recipientAddress.<key>`. Check the spelling of what you sent — and check
> you sent `currencySymbol`, `currencyId` and `relationshipToCustomer`, which
> are required on every add.

> **I sent recipientCountry and the country is still missing**
>
> There is no `recipientCountry` field. Send `countryId` at the top level and
> inside `recipientAddress` — the one inside `recipientAddress` is the country
> saved on the recipient.

> **The same customer can add a USDC recipient but gets 403 on a SEPA one**
>
> Different providers, different verification. `CRYPTO` needs Sumsub; SEPA is
> Bridge-backed and needs Bridge KYC.

> **My customer has completed Bridge KYC but a SWIFT recipient still returns 403**
>
> `SWIFT` is settled by Keyrails, not Bridge, so it asks for **Keyrails**
> onboarding. Bridge KYC does not satisfy it, and completing it would not help: a
> SWIFT quote already requires the same Keyrails verification before it will
> price, so the recipient would be unusable either way.

> **My recipient was created but a transfer to it fails**
>
> On a Bridge-backed rail the recipient exists before it is verified. Poll
> [Get counterparty checks](https://docs.endl.io/api-reference/recipients/get-counterparty-checks.md)
> until `status` is `ACTIVE`.

> **I am waiting for a webhook telling me the recipient is verified**
>
> None is emitted. Recipients produce no events at all — poll.

> **I want to correct a typo in a recipient's account number**
>
> There is no update endpoint. Add a corrected recipient and delete the old one.

> **Supported rails returns 400**
>
> `deposit_currency` and `payout_currency` are both mandatory query parameters.
> There is no unfiltered listing.

> **List recipients returns nothing**
>
> It is a `POST` with a body, and `size: 0` means *every* recipient, not none.
> Check you are not sending `size: 0` expecting an empty page.

> **The recipient was created, but the payout says the bank is missing**
>
> You sent the bank as `bankId` (the Get recipient fields key) or misspelled it.
> Send it as `providerBankId`.

> **My dateOfBirth is rejected as Invalid Date Format**
>
> Send it as `DD-MM-YYYY`, for example `25-01-1994`.

> **A UUID in the path returns 400 or 404**
>
> Path ids are reference ids: customers are `cus_…`, recipients are `rec_…`. A
> wrongly-shaped `rec_…` id is a `400`; a well-formed but unknown one is a `404`.
> A `{userId}` that doesn't resolve — a UUID, malformed, unknown or deleted — is
> always `404 ERRREF_1001`.

## Glossary

| Term | Meaning |
| - | - |
| Recipient | Saved payout instructions for one party, in one currency, on one rail. |
| Payout rail | How money reaches the recipient — `ACH`, `SEPA`, `SWIFT`, `IMPS`, `CRYPTO`, `AED_LOCAL`, … |
| Counterparty | The provider-side record of the recipient. Only Bridge-backed rails have one. |
| Counterparty status | The recipient's provider-side verification state. `ACTIVE` means ready. |
| Penny drop | A tiny real transfer used to verify an Indian account on IMPS. |
| Relationship | How the recipient relates to the customer — required on every add. |
| Reference id | A prefixed public identifier — `rec_`, `cus_`, `wlt_`, `acct_`, `txn_`, `qut_`. |

> [!NOTE]
>
> Written against `Api-Version: 2026-09.1`, from the behaviour of the `/api/v0`
> recipients surface. Rail availability and required fields are configuration and
> vary by customer and corridor — read them from
> [List supported rails](https://docs.endl.io/api-reference/recipients/list-supported-rails.md) and
> [Get recipient fields](https://docs.endl.io/api-reference/reference/get-recipient-fields.md)
> rather than hardcoding this page.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.