# Beneficiaries

A beneficiary is a person or business you pay. Save one, then send transfers with its `beneficiaryId` instead of repeating the bank details every time.

## When to use it

Saving is optional. [Create a transfer](api:createSingleTransfer) also accepts full `beneficiaryDetails`, and in that case Multigate saves the beneficiary for you (or reuses the matching saved one), with the same checks as below. So your beneficiary list also contains everyone you paid with `beneficiaryDetails`.

Save beneficiaries yourself when you want to check and approve bank details once, before the first payment.

## Prerequisites

- An API user with the *manage beneficiaries* permission to save, update and delete, or *view beneficiaries* to list and read.
- The beneficiary's bank code from [List banks](api:listBanks), or the bank's BIC (SWIFT code: the 8- or 11-character international bank identifier, for example `GTBINGLA`).

## IDs you'll use

| ID | Where you get it | Where you send it |
|---|---|---|
| Your client ID (`MG_CLIENT_ID`) | `currentAuthenticatedClientId` in [Get the current user](api:getCurrentUser) | `clientId` in the body of every save. |
| Customer ID | `entityId` from [Create a customer](api:createSubClient) | `subClientId` when you save for a customer; `clientEntityId` to list its beneficiaries. |
| Beneficiary ID | `beneficiary.entityId` from [Create a beneficiary](api:createBeneficiary), or `entityId` in [List beneficiaries](api:listBeneficiaries) | `beneficiaryId` in [Create a transfer](api:createSingleTransfer); the `{entityId}` in get, update and delete URLs. |

## Save a beneficiary

<Steps>
<Step title="Check the account name (NGN)">

For a Nigerian account (a 10-digit NUBAN, Nigeria's standard account number), ask the bank for the account holder's name first. This is called a name enquiry:

```bash
curl -X POST "$MG_BASE_URL/client-service/api/v1/beneficiaries/validate" \
  -H "mp-api-key: $MG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "bankAccountNumber": "0123456789", "bankCode": "058", "currencyIso3Code": "NGN", "countryIso3Code": "NGA" }'
```

```json
{
  "message": "beneficiary successfully validated",
  "nameEnquiryResponse": { "accountName": "ADA OKAFOR", "bankName": "Guaranty Trust Bank" }
}
```

The response is always `200`. When the account can't be verified, `nameEnquiryResponse` is `null`: don't save or pay that account until the number is corrected.

</Step>
<Step title="Save it">

Use the name the bank returned as `accountName`:

```bash
curl -X POST "$MG_BASE_URL/client-service/api/v1/beneficiaries" \
  -H "mp-api-key: $MG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "Ab3kP9xQ2mN7vR1sT4uV6",
    "name": "Ada Okafor",
    "accountName": "ADA OKAFOR",
    "accountNumber": "0123456789",
    "bankBicOrCode": "058",
    "bankName": "Guaranty Trust Bank",
    "currencyIso3Code": "NGN",
    "country": "NGA",
    "addressLine1": "12 Marina Road",
    "city": "Lagos",
    "state": "Lagos"
  }'
```

```json
{
  "message": "beneficiary created",
  "beneficiary": {
    "entityId": "Bn4kQ8rT2vX6yZ1aC3dEf",
    "name": "Ada Okafor",
    "accountName": "ADA OKAFOR",
    "accountNumber": "0123456789",
    "bankBicOrCode": "058",
    "bankName": "Guaranty Trust Bank",
    "bankCountry": "NGA",
    "currencyIso3Code": "NGN",
    "country": "NGA",
    "postCode": "000000",
    "status": "active",
    "clientEntityId": "Ab3kP9xQ2mN7vR1sT4uV6",
    "subClientId": "",
    "isPlatformAccount": false,
    "beneficiaries": []
  }
}
```

The response is shortened here. **Store `beneficiary.entityId`**: it's the `beneficiaryId` for transfers. The beneficiary is `active` straight away; no webhook is sent.

</Step>
<Step title="Pay it">

```json
{
  "uniqueRequestId": "po_20261010_0002",
  "reference": "Supplier payment Oct",
  "amount": 125000,
  "sourceCurrencyIso3Code": "NGN",
  "sourceAccountNumber": "1029384756",
  "beneficiaryId": "Bn4kQ8rT2vX6yZ1aC3dEf"
}
```

Send this body to [Create a transfer](api:createSingleTransfer). `sourceAccountNumber` is the wallet you pay from (see [IDs and numbers you'll use](02-accounts.md#ids-and-numbers-youll-use)). Send `beneficiaryId` **or** `beneficiaryDetails`, never both. See [Payouts](05-payouts.md).

</Step>
</Steps>

## Rules by currency

Every save needs `clientId`, `name`, `accountName`, `accountNumber`, `bankBicOrCode`, `bankName`, `currencyIso3Code`, `country`, `addressLine1`, `city` and `state`. What goes in the bank fields depends on the currency:

| Currency | `country` | `accountNumber` | `bankBicOrCode` | Checked with the bank? | Also send |
|---|---|---|---|---|---|
| NGN | `NGA` | 10-digit NUBAN | Bank code from [List banks](api:listBanks) (for example `058`), or a BIC (translated to the local code) | Yes. Production refuses an account the bank can't confirm. | `accountName` from the [name check](#check-an-account) |
| GHS | `GHA` | The local account number | The local bank code for the bank's country, or a BIC | No | |
| XOF | The bank's country, for example `SEN` or `CIV` | The local account number | The local bank code for that country, or a BIC | No | |
| ETB | `ETH` | The local account number | The local bank code, or a BIC | No | |
| SGD | `SGP` | The local account number | Saved as sent; not checked | No | |
| USD, EUR, GBP and other currencies | The beneficiary's country, for example `DEU` | The account number, or the IBAN where the country uses one | The bank's BIC (8 or 11 characters) | No | A real `postCode` (it defaults to `000000`); `intermediaryBank` if the payment must go through a correspondent bank |

`bankBicOrCode` must match a bank in Multigate's bank list. The saved code is normalised: the local bank code for NGN, GHS, ETB and XOF, the bank's BIC for other currencies, so it can differ from what you sent. For a local code, `country` must be the bank's country. The name you send in `accountName` is saved as it is; it isn't compared with the bank's.

- **Upper-case codes.** Send `currencyIso3Code` and `country` in upper case. A lower-case currency is saved as sent and treated as international, so an NGN account isn't checked.
- **Letters and digits only** in `accountNumber`: no spaces or dashes.
- **Duplicates.** The same account number, currency and bank can be saved once per business and once per customer (`409` "beneficiaries already exist"). An 8-character BIC and its 11-character `XXX` form count as the same bank.
- **Email.** Production refuses disposable email domains such as yopmail.com ("Email domain is not allowed").

:::caution[The sandbox saves NGN accounts the bank can't find]
In the sandbox, a failed NGN account check doesn't stop the save, so a wrong account number is accepted there and refused in production. Sandbox name lookups are answered by test banks, so names can be fixed test values. See [Sandbox vs production](../01-get-started/05-sandbox-vs-production.md#beneficiaries-and-name-enquiry).
:::

## Beneficiaries for your customers

Add `subClientId` (the customer ID) when you save a beneficiary for one of your customers. That beneficiary belongs to the customer: use it for the customer's payouts.

- **Listing.** [List beneficiaries](api:listBeneficiaries) returns only your own business's beneficiaries unless you pass the customer ID in `clientEntityId`.
- **Reading, updating, deleting.** Today these endpoints only find your own business's beneficiaries. For a customer's beneficiary they return `400` "beneficiary not found". Read it through the list instead; to change its bank details, save a new beneficiary.

## Statuses

A saved beneficiary is always `active`. Deleted beneficiaries are no longer returned.

Some international payout channels need the beneficiary registered with them before they pay. Multigate does this automatically the first time you pay the beneficiary through such a channel, and shows the registration as an entry in the beneficiary's `beneficiaries` array. The transfer stays `processing` until the registration is ready, and fails (with the money returned) if it's refused.

```mermaid
stateDiagram-v2
    direction LR
    [*] --> processing: first transfer through the channel
    processing --> active: channel accepts the beneficiary
    processing --> failed: channel refuses it
    active --> [*]
    failed --> [*]
```

| Registration `status` | Meaning | Waiting transfer |
|---|---|---|
| `processing` or `pending` | Being registered with the channel. | Stays `processing`. |
| `active` | Ready. | Is sent. |
| `failed` | The channel refused the beneficiary. | Fails, and the debit is reversed. |

Updating a beneficiary discards its registrations, so the next transfer through that channel waits again. In the sandbox, registrations can take much longer than in production.

## How it works

```mermaid
sequenceDiagram
    autonumber
    participant You as Your backend
    participant MG as Multigate
    participant Bank as Beneficiary's bank
    You->>MG: POST /beneficiaries/validate (NGN)
    MG->>Bank: Name enquiry
    Bank-->>MG: Account name
    MG-->>You: 200, nameEnquiryResponse
    You->>MG: POST /beneficiaries
    MG->>MG: Check bank code, duplicates
    MG->>Bank: Account check (NGN)
    MG-->>You: 200, beneficiary active
    You->>MG: Create a transfer with beneficiaryId
    MG-->>You: 200, transfer processing
```

## Check an account

| Use | When | If the account can't be verified |
|---|---|---|
| [Validate a beneficiary account (NGN)](api:validateBeneficiaryAccount) | Nigerian accounts. The lookup always uses the Nigerian network. | `200` with `nameEnquiryResponse: null`. |
| [Look up an account name](api:nameEnquiry) | Other local rails. | An error response. |

## Manage beneficiaries

| Action | Endpoint | Notes |
|---|---|---|
| List | [List beneficiaries](api:listBeneficiaries) | Oldest first. Page with `pageOffset` and `pageSize`. Filter by `accountName`, `sourceAccountNumber`, `sourceBankBicOrCode` or `sourceCurrencyIso3Code`. `404` when nothing matches. |
| Get | [Get a beneficiary](api:getBeneficiary) | Your own business's beneficiaries only. |
| Update | [Update a beneficiary](api:updateBeneficiary) | Send only what changes, but always send `postCode` if it was set, or it resets to `000000`. Changing bank details repeats the bank checks. The response can leave out unchanged fields: read the beneficiary again. |
| Delete | [Delete a beneficiary](api:deleteBeneficiary) | It can't be used for new transfers. Past transfers are unaffected, and you can save the same account again. |

## Errors and recovery

| Status | Message | Cause | What to do |
|---|---|---|---|
| `400` | Invalid Bank or Swift code | The code isn't in Multigate's bank list for that `country`, or the bank has no BIC (non-local currencies). | Check the code with [List banks](api:listBanks), or send the BIC. |
| `400` | Invalid beneficiary account number | Production, NGN: the bank couldn't confirm the account. | Check the number with [Validate a beneficiary account (NGN)](api:validateBeneficiaryAccount). |
| `400` | Sub-Client currently in {status} status | The customer is rejected, inactive, blocked or deleted. | Use an active customer. |
| `400` | beneficiary not found | Get, update or delete of an unknown, deleted or customer's beneficiary. | Check the ID with [List beneficiaries](api:listBeneficiaries). |
| `400` | Validation error | A required field is missing or too long, or `accountNumber` has spaces or symbols. | Fix the fields listed in `errors`. |
| `404` | Client not found | `clientId` or `subClientId` isn't you or one of your customers. | Use your client ID and your customers' IDs. |
| `404` | Currency not found, Country not found | The code isn't supported. | Use an upper-case ISO code Multigate supports. |
| `404` | beneficiary not found | List: nothing matches, or the page is past the last one. | Relax the filters or go back a page. |
| `404` | Resource not found | Your API user lacks the permission. | Ask your administrator for the permission. |
| `409` | beneficiaries already exist | The account is already saved. | Find it with `sourceAccountNumber` and use its `entityId`. |

Beneficiaries send no webhooks or emails.

## Next steps

- [Payouts](05-payouts.md): pay a saved beneficiary.
- [Bulk payouts](06-bulk-payouts.md): pay many beneficiaries at once.
- [Acting for your customers](../02-concepts/06-acting-for-customers.md): customer IDs and `onBehalfOf`.
