# Accounts

Accounts hold, receive and send money. This page covers every account type, how to open each one, and how to use it.

## Account types

| Type | `accountType` | What it is | Use it to |
|---|---|---|---|
| **Wallet** | `wallet` | A balance in one currency on the Multigate ledger, for you or a customer. | Hold funds, pay out, convert. |
| **Virtual account** | `viban` | A dedicated bank account number in the account holder's name, issued by a partner bank and attached to a wallet. Money paid to it lands in the wallet. | Give payers an account number to send money to. |
| **Dynamic virtual account** | `wallet` with `isDynamic: true` | An NGN virtual account that accepts **one** payment of an exact amount, then closes. | Collect a specific invoice or order. |
| **Linked account** | `linked` | A bank account your business already holds at another bank, connected to Multigate. The money stays at your bank. | Pay out from your existing bank accounts and see their balances and statements through the API. |
| **Receivable account** | `receivable` | An account opened for one invoice. | Match payments to invoices automatically (see [Receivables](11-receivables.md)). |

```mermaid
flowchart LR
    subgraph Multigate ledger
        wallet[(Wallet NGN)]
    end
    va1[Virtual account<br/>Partner bank A] --> wallet
    va2[Virtual account<br/>Partner bank B] --> wallet
    payer([Payer]) -->|bank transfer| va1
    wallet -->|payouts, conversions| out([Beneficiaries])
    subgraph Your bank
        linked[(Linked account)]
    end
    linked -->|payouts via your bank| out
```

## IDs and numbers you'll use

An account has an ID and up to three kinds of number. Mixing them up is the most common integration mistake.

| Name | Example | Where you get it | Use it for |
|---|---|---|---|
| **Account ID** (`accountId`) | `4b8e1f20-…` | `account.accountId` from [Create an account](api:createAccount) or [List accounts](api:listAccounts). [Get an account by ID](api:getAccountById) calls it `entityId`. | [Get an account by ID](api:getAccountById), conversions (`sourceAccountId`, `targetAccountId`), [Get a dynamic account's details](api:getDynamicAccountDetails). |
| **Wallet number** | `1029384756` | `account.accountNumber` from [Get an account by ID](api:getAccountById), or `accountBalance.accountNumber` from [Get an account balance](api:getAccountBalance). | Payouts (`sourceAccountNumber`), balances, statements. It's a Multigate ledger number, not a bank account: payers can't send money to it. |
| **Virtual account number** | `9912345678` | `fundingDetails[].accountNumber` | Give it to payers. It arrives as `receivingAccountNumber` in the inflow webhook. Balances and statements also accept it and return the wallet's. |
| **Linked account number** | `1011223344` | Your own bank account number. | Payouts, balances and statements for a linked account. |
| **Account holder ID** (`clientId`, and `entityId` in account lists) | `Kx81mQ2pZr4tV9wYa3Bc5` | The same account responses. | Tells you whose account it is: your client ID, or the customer's `entityId`. It isn't the account's ID. |

:::caution[`entityId` means two things]
In [Create an account](api:createAccount), [List accounts](api:listAccounts) and [Get an account](api:getAccount), `entityId` is the **account holder's** ID. In [Get an account by ID](api:getAccountById), `entityId` is the **account's** ID (the same value as `accountId`). Store `accountId` and the holder's ID in separate fields.
:::

## Wallets and virtual accounts

:::caution[Sandbox account numbers are test numbers]
Sandbox virtual accounts come from bank test systems; real transfers to them never arrive, and some show test bank codes such as `test-bank`. Fund them with [Simulate an inflow](api:simulateInflow), and always read bank names and codes from the API. See [Sandbox vs production](../01-get-started/05-sandbox-vs-production.md#inflows-and-virtual-accounts).
:::

### Before you open one

- You've completed the [Quickstart](../01-get-started/03-quickstart.md) environment setup (`MG_BASE_URL`, `MG_API_KEY`).
- Your business is active. To open an account for a customer, the customer is `active` and you have its `entityId` (see [Customers](01-customers.md)).
- Multigate has set up at least one partner bank (a bank that issues virtual accounts for Multigate) for you in the currency. Otherwise the request fails with `404` "Partner/Client mapping not found".
- You have accepted that partner bank's terms of service in the dashboard. Otherwise: `400` "One or more required terms of service have not been accepted for …".
- Your API user has the *manage accounts* permission.

You don't send KYC details: Multigate uses the account holder's profile on file (registered business name, contact email and phone).

### Open an account

| Field | Required | What to send |
|---|---|---|
| `uniqueRequestId` | Yes | A new ID of your own for this request (an idempotency key: it stops a retry from opening a second account). See [Retries and duplicates](#retries-and-duplicates). |
| `currencyIso3Code` | Yes | Upper-case ISO 4217 code, for example `NGN`. |
| `accountName` | Yes | Your name for the wallet, up to 100 characters: letters, digits, spaces and `& ' ( ) * + , - . / :`. |
| `onBehalfOf` | For a customer | The customer's `entityId`. Leave it out for your own business. |
| `countryIso3Code` | XOF only | The account's country, for example `SEN`. |
| `partnerCodes` | No | Only open virtual accounts at these partner banks, for example `["214", "057"]`. See [Choosing the partner banks](#choosing-the-partner-banks). |
| `amount` | Dynamic accounts only | See [Dynamic accounts](#dynamic-accounts). |

```bash
curl -X POST "$MG_BASE_URL/client-service/api/v1/accounts" \
  -H "mp-api-key: $MG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "uniqueRequestId": "acct_20261010_0001",
    "currencyIso3Code": "NGN",
    "accountName": "Kola Stores Collections",
    "onBehalfOf": "Kx81mQ2pZr4tV9wYa3Bc5"
  }'
```

```json
{
  "message": "account created",
  "account": {
    "accountId": "Ac4mW8pZ2kR6tY1nQ7xVb",
    "clientId": "Kx81mQ2pZr4tV9wYa3Bc5",
    "entityId": "Kx81mQ2pZr4tV9wYa3Bc5",
    "uniqueRequestId": "acct_20261010_0001",
    "currencyIso3Code": "NGN",
    "accountName": "Kola Stores Collections",
    "status": "active",
    "accountType": "wallet",
    "isDynamic": false,
    "fundingDetails": [
      { "accountName": "Kola Stores Ltd", "accountNumber": "9912345678", "bankName": "Partner Bank", "bankOrSortCode": "000017", "bankCountry": "NGA", "countryIso3Code": "NGA" }
    ]
  }
}
```

**Store** `account.accountId`, your `uniqueRequestId`, the account holder (`onBehalfOf`, or your own business) and every `fundingDetails[].accountNumber`. You need the virtual account numbers to tell which customer an inflow belongs to (see [Collections](03-collections.md#match-an-inflow-to-your-customer-or-order)).

**Is it ready?** If `status` is `active` and `fundingDetails` lists at least one account number, payers can pay into it now. If `status` is `processing` or `pending`, see [When the account isn't active yet](#when-the-account-isnt-active-yet). If the call returned `400` `account failed`, no bank opened it.

- **One wallet, possibly several virtual accounts.** Multigate requests a virtual account at each partner bank configured for you in that currency. Each active one appears in `fundingDetails`; give payers any of them.
- **Two names.** The wallet's `accountName` is the name you sent. Virtual accounts are opened at the bank in the account holder's registered business name, which is what payers see (`fundingDetails[].accountName`).
- **The wallet's own number isn't in this response.** Get it from [Get an account by ID](api:getAccountById) (`account.accountNumber`) when you need it for payouts.
- **XOF:** send `countryIso3Code` with the account's UEMOA (West African Economic and Monetary Union) country, for example `SEN`; the default is `CIV`.
- **ETB:** payers pay into a shared account and must quote the `fundingReference` shown in `fundingDetails`.
- **Wallets without virtual accounts.** Some foreign-currency wallets are opened without any virtual account: `fundingDetails` stays empty, and you fund them by [conversion](09-fx-conversions.md). The exception is a USD wallet with a [USD bank account](#usd-bank-account-veem).

### What to give payers

From one entry of `fundingDetails` (for a dynamic account, from `data.fundingDetails` in [Get a dynamic account's details](api:getDynamicAccountDetails)):

| Tell the payer | Field |
|---|---|
| Account number | `accountNumber` |
| Account name | `accountName` (the registered business name, not your wallet name) |
| Bank | `bankName` (and `bankOrSortCode` if their bank asks for a code) |
| Reference (ETB only) | `fundingReference`: the payer must quote it, or the money can't be matched |
| Exact amount (dynamic accounts only) | The `amount` you opened it with. Any other amount isn't credited. |

Always read these values from the API; don't hard-code bank names or codes.

### Retries and duplicates

`uniqueRequestId` must be new for each account holder (your business, or each customer).

- Reusing it is refused with `400` "uniqueRequestId has already been used", **even if the earlier attempt failed**. The earlier account isn't returned.
- If a request times out, don't resend it straight away: call [List accounts](api:listAccounts) (with `onBehalfOf` for a customer) and look for your `uniqueRequestId`. Only if it isn't there, wait a minute, look again, then resend with the **same** `uniqueRequestId`: if the first attempt landed meanwhile you get `400` "uniqueRequestId has already been used" and no second account.
- Never send two requests with the same `uniqueRequestId` at the same time: both can open an account.
- Some partner banks allow only one account per account holder in a currency. A second local-currency account then skips that bank; a second foreign-currency account is refused with `409` "account already exist" when every such bank already has one.
- **Foreign currencies:** if the account holder already has a wallet in that currency and Multigate has set up a bank that issues virtual accounts in it, the new virtual accounts are added to that wallet, and the response is that wallet with its original `uniqueRequestId`. After a timeout, look for that wallet in [List accounts](api:listAccounts), not for your new `uniqueRequestId`.

### When the account isn't active yet

Local-currency virtual accounts (NGN, GHS, ETB, XOF) are requested during the call. Some partner banks confirm later, and some foreign-currency banks first review your business profile. The account then comes back `processing` (or `pending`) with an empty `fundingDetails`. There's no fixed waiting time: it depends on the partner bank. Don't give payers anything until the account is `active`.

```mermaid
stateDiagram-v2
    direction LR
    [*] --> processing: requested
    [*] --> active: a bank opened it straight away
    [*] --> failed: every bank refused (400 account failed)
    processing --> active: a partner bank confirms
    processing --> failed: every partner bank refused
    active --> disabled: dynamic account paid, or business suspended
```

| Status | Meaning | What to do |
|---|---|---|
| `processing`, `pending` | Waiting for a partner bank. | Wait for `account_opened`. |
| `profiling` | Waiting for the bank to approve your business profile (virtual accounts only). | Wait for `account_opened`; it's often not sent on this path, so also poll [Get an account by ID](api:getAccountById). |
| `active` | At least one virtual account is open (or the wallet needs none). | Use it. |
| `failed` | Every bank refused. | Open a new account with a new `uniqueRequestId`, or contact support. |
| `inactive`, `disabled` | Closed or blocked. | It can't receive or send money. |
| `enabled` | Re-enabled after being disabled. Today it can't send money until Multigate sets it back to `active`. | Contact support. |

In [Create an account](api:createAccount), [List accounts](api:listAccounts) and [Get an account](api:getAccount), an account in any status other than `active` comes back without the holder's `entityId` and with an empty `fundingDetails`. Use `accountId` and `status` to recognise it.

Wait for the [`account` / `account_opened`](webhook:account.account_opened) webhook, whose `fundingDetails` lists the new account numbers. You can receive it more than once for one account, as each partner bank activates.

:::warning[No webhook when an account fails later]
If every bank refuses during the call, you get `400` `account failed` straight away. If a bank refuses **later**, no webhook is sent: the account turns `failed` silently, or, for some foreign-currency banks, stays `processing`. Poll [Get an account by ID](api:getAccountById) for accounts that stay `processing` (for example hourly), and alert after a day.
:::

### Choosing the partner banks

By default, Multigate opens a virtual account at **every** partner bank set up for you in that currency, so your payers can choose between several account numbers. To control which banks your customers' account numbers come from, list them in `partnerCodes`, using the partner bank codes Multigate gives you when it sets you up:

```json
{ "uniqueRequestId": "acct_kola_ngn_214", "currencyIso3Code": "NGN", "accountName": "Kola Stores", "onBehalfOf": "Kx81mQ2pZr4tV9wYa3Bc5", "partnerCodes": ["214"] }
```

Multigate then requests virtual accounts from those banks only. The wallet starts `processing` as usual.

| Response | Meaning |
|---|---|
| `404` "Partner not found" | One of the codes isn't a partner bank code Multigate knows. |
| `404` "Partner(s) not allowed 057" | A code is a real partner bank, but it isn't set up for this account holder in this currency. The message lists the codes that aren't allowed. Remove them, or ask Multigate to add that bank to your setup. |

### Dynamic accounts

A dynamic account is an NGN virtual account for one payment, for example one order. Payments into it are swept (moved automatically) to your **pool account**: one wallet Multigate sets up to collect money paid into many dynamic accounts.

Use a dynamic account when each payment must match what you're owed. A reusable account accepts any amount, so a payer can send too little or too much and you have to chase the difference or refund it. A dynamic account only accepts the exact amount, and only once: the payer must pay the full amount in **one** transfer. A part payment isn't credited, and the payer can't top it up later.

Add `amount` (NGN only, in naira, at most 2 decimals) to open one:

```json
{ "uniqueRequestId": "order_5521", "currencyIso3Code": "NGN", "accountName": "Order 5521", "amount": 125000 }
```

1. Call [Get a dynamic account's details](api:getDynamicAccountDetails) with the returned `accountId`, and give your payer `fundingDetails.accountNumber`: that is the single-payment account.
2. When exactly that amount arrives and clears screening, the money is credited to your pool account (`sweepsTo`), and you receive the [`account` / `inflow`](webhook:account.inflow) webhook. Its `receivingAccountNumber` is the dynamic account; its `accountId` is the **pool account's**.
3. The dynamic account then closes: `status` becomes `disabled`, and `receivedAmount`, `reference` and `transactionDate` are filled in. No separate webhook or email announces the closure; read the details endpoint.
4. Give your payer a receipt with [Download a dynamic account receipt](api:downloadDynamicAccountReceipt).

Dynamic accounts need a pool account and a partner bank that supports them, both set up by Multigate. Otherwise the request fails with `400` and a message saying which is missing.

A payment of any other amount isn't credited and sends no webhook. Depending on the bank, it is refused before it reaches Multigate, or it is rejected and your business contact receives a "Rejected Inflow Transaction" email (whose text says the account is disabled). Ask the payer to send the exact amount; contact support to recover a wrong payment.

`expiryDate` is passed to the bank, but most banks ignore it: don't rely on it to close the account.

### USD bank account (Veem)

If Multigate has set your business up for it, your USD wallet can get its own **USD bank account**: an account in your business's name, provided by Multigate's partner Veem, that payers anywhere can send USD to by international (SWIFT) transfer. Without one, a USD wallet can only be funded by [conversion](09-fx-conversions.md). Money paid into it lands in your USD wallet, ready to pay out or convert.

```mermaid
sequenceDiagram
    autonumber
    participant You
    participant MG as Multigate
    participant Veem
    participant Payer
    You->>MG: POST /accounts (USD)
    MG->>Veem: Application for a USD bank account
    MG-->>You: USD wallet (processing, or your existing wallet)
    Note over Veem: Veem reviews the application
    Veem-)MG: Approved
    MG-)You: account / account_opened, with fundingDetails
    Payer->>Veem: USD transfer to your account details
    Veem-)MG: Payment received
    Note over MG: Screened like any inflow
    MG-)You: account / inflow, USD wallet credited
```

**Who can have one:** your own business only, not your [customers](01-customers.md), and only in USD. Multigate turns it on for you; before it can, your business must be approved by Veem (Multigate shares your onboarding details with them) and someone in your business must have accepted Veem's terms of service in the dashboard.

**Open it** with [Create an account](api:createAccount) in `USD`, without `onBehalfOf`:

```json
{ "uniqueRequestId": "acct_usd_vba_0001", "currencyIso3Code": "USD", "accountName": "Kola Stores USD" }
```

Multigate sends Veem an application using the business details from your onboarding (registered name and number, incorporation date, the countries you operate in and pay to, and your website). You don't send them again. Then:

| Situation | What the response shows | What happens next |
|---|---|---|
| You have no USD wallet yet | A new USD wallet, `status: processing`, `fundingDetails: []`. | The wallet becomes `active` when Veem approves. |
| You already have a USD wallet | Your existing wallet, unchanged (its `accountId`), still `active`. | The bank account is added to it when Veem approves. Your balance isn't affected. |
| The application can't be sent (for example, Veem hasn't approved your business yet) | A new wallet comes back with `status: failed`; an existing wallet comes back unchanged. | Ask Multigate to complete your Veem setup, then send a new request with a new `uniqueRequestId`: Multigate retries the same application. |
| A USD bank account is already open or under review | `409` "account already exist". | Nothing to do: use the one you have. |

If Multigate sets this up after you already hold a USD wallet, it applies for you automatically: you don't need to call anything.

**When Veem approves** (this can take days; Veem may ask Multigate for more information), you receive [`account` / `account_opened`](webhook:account.account_opened) for the USD wallet, once, with the new entry in `fundingDetails`. It also appears in [List accounts](api:listAccounts) and [Create an account](api:createAccount) responses from then on.

**What to give payers** from that `fundingDetails` entry:

| Payer's form asks for | Use |
|---|---|
| Account name | `accountName` (your registered business name) |
| Account number or IBAN | `accountNumber` (an IBAN) |
| SWIFT / BIC code | `bic` |
| Bank name and address | `bankName`, `bankAddress` |
| Bank country | `bankCountry` |

Ignore `bankOrSortCode` on this entry: it holds the internal value `veem`, not a bank code. Only these international (SWIFT) details are shown today; US domestic details (ACH or wire routing numbers) aren't available through the API.

**Payments in** are handled like any other [inflow](03-collections.md): screened, credited to your USD wallet, then announced by [`account` / `inflow`](webhook:account.inflow). Only completed payments are credited.

:::caution[No signal while it's under review, or if it's refused]
While Veem reviews the application, nothing in the API shows its progress: a USD wallet's details don't list pending bank accounts. If Veem refuses it, no webhook or email is sent and the wallet keeps its previous status (a new wallet stays `processing`). If you're waiting for the account and `account_opened` hasn't arrived, ask Multigate for the application's status.
:::

### Find your accounts

| You have | Use |
|---|---|
| Nothing; want them all | [List accounts](api:listAccounts) (filter by `currencies`, `statuses`, `accountTypes`). Without `onBehalfOf` it lists **your business's** accounts only; pass a customer's ID for theirs. |
| A wallet, virtual or linked account number | [Get an account](api:getAccount), which includes the balance |
| An `accountId` | [Get an account by ID](api:getAccountById), which shows the wallet's own number and, for local currencies, every virtual account in any status |

## Linked accounts

A linked account connects a bank account your business already holds, at your local or international bank, to Multigate. The money stays at your bank. This is the API side of Multigate's **Multi-Bank Connector**: see balances, pull statements and make centralised payments from any of your banks through one integration.

### How linking works

```mermaid
sequenceDiagram
    autonumber
    participant Maker as Your API user
    participant MG as Multigate
    participant Checker as Your approver
    participant Bank as Your bank
    Maker->>MG: GET banks you can link
    Maker->>MG: GET the bank's documents, download templates
    Maker->>MG: POST upload signed documents
    Maker->>MG: POST submit linking request
    MG-->>Checker: Email: Bank Account Linking Request
    Checker->>MG: PATCH approve
    MG->>Bank: Checks the account (local currencies)
    MG-->>Bank: Email: request approved, documents attached
    Note over MG: Linked account created, status active
    Maker->>MG: Upload bank API credentials (local accounts)
```

```mermaid
stateDiagram-v2
    direction LR
    [*] --> PENDING: submitted
    PENDING --> APPROVED: another user approves (linked account created)
    PENDING --> DECLINED: another user declines
    PENDING --> PENDING: approval failed (fix and approve again)
```

<Steps>
<Step title="Pick the bank">

[List banks you can link](api:listLinkingBanks), optionally filtered by `countryIso3Code` or `bankName`. Note the bank's `bankId`.

</Step>
<Step title="Prepare the bank's documents">

Local accounts need the documents the bank asks for, such as a signed mandate. [List a bank's linking documents](api:listBankTemplates), download each blank template with [Download a linking document](api:downloadLinkingDocument), complete and sign it, then upload it with [Upload a linking document](api:uploadLinkingDocument) (PDF, DOC, DOCX, XLS or XLSX, up to 2 MB). Keep each returned `blobName` with its `templateId`.

SWIFT accounts need no documents (next step).

</Step>
<Step title="Submit the request">

```bash
curl -X POST "$MG_BASE_URL/client-service/api/v1/account-linking/submit" \
  -H "mp-api-key: $MG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "clientUUId": "Ab3kP9xQ2mN7vR1sT4uV6",
    "bankId": "Hq4nT8vW2xZ6cB1m",
    "countryCode": "NGA",
    "accountConfigurationTypes": ["Local/Domestic"],
    "bankAccountNumber": "1011223344",
    "accountName": "Acme Payments Ltd",
    "accountCurrency": "NGN",
    "accountOfficerEmail": "officer@bank.example",
    "documents": [ { "templateId": "Tm5pQ8rS2uV4wX7y", "blobName": "Lp2q8RnW4xY7zA-account-mandate-signed.pdf" } ]
  }'
```

- `clientUUId` is your client ID (`MG_CLIENT_ID`), or a customer's `entityId` to link the customer's account.
- `bankId` comes from step 1; each `templateId` and `blobName` from step 2.
- `countryCode` (ISO alpha-3) and `accountCurrency` are only checked at approval, so send valid codes.
- For a **SWIFT** account, send `"accountConfigurationTypes": ["SWIFT"]` and no documents. Multigate must have registered your BIC (your bank's 8- or 11-character SWIFT code), and the RMA (Relationship Management Application: the SWIFT setting that lets two banks exchange messages) between your BIC and the bank must be active before the request can be approved or declined.

The response's `accountLinking.entityId` identifies the request; its `ApprovalStatus` is `PENDING`. Several accounts at one bank? Use [Submit several linking requests](api:submitMultipleAccountLinking).

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

A **different user** in your business, with the *approve account linking* permission, approves the request with [Approve or decline a linking request](api:updateAccountLinkingStatus) or in the dashboard.

Approval creates the linked account straight away (`accountType` `linked`, status `active`, `accountNumber` = your bank account number) and emails your bank officer and the bank's linking contacts. For local currencies Multigate first checks the account with your bank. If anything fails, the request stays `PENDING`; fix the cause and approve again. For some banks, approval marks the request `APPROVED` without creating the account: if no linked account appears in List accounts, contact Multigate.

Track requests with [Search linking requests](api:searchAccountLinking) (filter `approvalStatus` = `PENDING`, `APPROVED` or `DECLINED`), and find the new account with [List accounts](api:listAccounts) (`accountTypes=linked`).

</Step>
<Step title="Upload bank credentials (local accounts)">

To pay out from a local linked account and see its live balance and statements, Multigate connects to your bank directly with API credentials your bank issues to you. This is available for your own business's accounts (pass your own client ID):

1. [List bank credential slots](api:listBankCredentials) and find your bank (`isProfiled` shows whether credentials are in).
2. [Download a bank credentials template](api:downloadBankCredentialsTemplate), fill one row per account with the credentials from your bank.
3. [Upload bank credentials](api:uploadBankCredentials). Check `failedUploads`; account numbers must be 10 digits. Uploading a row again replaces its credentials.

People in your business who manage credentials receive an "Account Activation Confirmation" email.

</Step>
</Steps>

### Using a linked account

| You want to | How | Notes |
|---|---|---|
| Pay out | [Create a transfer](api:createSingleTransfer) or bulk, with the linked account as `sourceAccountNumber` | Local accounts pay through your bank's API; SWIFT accounts send a SWIFT payment from your BIC. Approval rules apply. |
| See the balance | [Get an account balance](api:getAccountBalance) | Fetched live from your bank. Returns `"0"` if the bank can't be reached. |
| See transactions | [Get account transactions](api:getTransactionHistory) or [Download a statement](api:downloadAccountStatement) | Live from your bank (SWIFT: from MT940 statements, the standard SWIFT statement message). [Get an account statement](api:getAccountStatement) doesn't support SWIFT accounts. |
| Receive money | — | Payers pay your bank account directly; Multigate doesn't process inflows to linked accounts. |

:::warning[Payouts from local linked accounts can wait silently]
Multigate checks your bank balance before sending. If the balance is too low, or no credentials are uploaded, the transfer stays `processing` and is retried about every 5 minutes. No webhook tells you why. Keep the bank account funded and credentials uploaded, and alert on linked-account transfers that stay `processing`.
:::

### Linking rules and errors

| Message | Cause | What to do |
|---|---|---|
| The associated entity does not belong to this organisation | `clientUUId` isn't your client ID or an active customer's. | Use the right ID. |
| Bank account to link already exist | This account was already requested at this bank, whatever happened to that request. | Search your requests. A declined account can't be requested again: contact Multigate. |
| The required document is missing. / Template not found. | A required template has no document, or a `templateId` isn't this bank's. | Upload and send every required document. |
| Too many documents uploaded… | More documents than the bank has templates. | Send one document per template. |
| Client not mapped to bic | SWIFT linking before Multigate registered your BIC. | Contact Multigate. |
| You cannot approve a request that you have raised yourself. | The approver is the submitter. | Approve with another user. |
| RMA Setup not completed. | SWIFT relationship with the bank isn't active yet. | Wait for the RMA, then approve. |
| account verification with third party failed | Your bank didn't confirm the account at approval. | Check the account number, then approve again. |
| Account linking already processed | The request was already approved or declined. | None. |

Linking sends no webhooks, and no `account_opened` event for the new linked account. Approvers are notified by email.

## Next

<CardGroup cols={2}>
<Card title="Collections" icon="lucide-arrow-down-to-line" href="03-collections.md">
What happens when money arrives in a virtual account.
</Card>
<Card title="Balances and statements" icon="lucide-file-text" href="10-balances-and-statements.md">
Reconcile every account.
</Card>
</CardGroup>
