# Remittance companies (IMTOs)

Pay out money that senders abroad paid you, into beneficiaries' local bank accounts, with the sender and beneficiary details regulators require.

**Who it's for:** remittance companies, that is licensed international money transfer operators (IMTOs), paying out into African corridors.

## Architecture

```mermaid
flowchart LR
    sender([Sender abroad]) -->|pays you| app[Your app and backend]
    app -->|pre-fund| acct[(Your NGN account on Multigate)]
    app -->|name enquiry, then remittance| mg[Multigate API]
    acct -->|debited amount + fee| mg
    mg -->|local payment| bank([Beneficiary's bank])
    mg -.->|transfer_completed or transfer_failed| app
```

```mermaid
sequenceDiagram
    autonumber
    participant App as Your app (sender abroad)
    participant You as Your backend
    participant MG as Multigate
    participant Bank as Beneficiary bank
    App->>You: Sender pays you abroad
    You->>MG: Look up the beneficiary's account name
    MG-->>You: responseCode 00, bankAccountName
    You->>MG: Initiate a remittance (sender, beneficiary, uniqueRequestId)
    MG-->>You: 200, data.status pending, pending_approval or processing
    Note over MG: Screening, approval, debit
    MG->>Bank: Local payment
    MG-)You: transfer / transfer_completed or transfer_failed
    You-->>App: Notify the sender
```

## Before you start

- [ ] A sandbox API key, and `MG_BASE_URL` and `MG_API_KEY` set as in the [Quickstart](../01-get-started/03-quickstart.md).
- [ ] A webhook URL registered ([Webhooks overview](../03-webhooks-and-emails/01-overview.md)).
- [ ] Your API user has the *initiate payment* or *approve payment* permission. Whether its remittances also wait for an approver follows the same rules as transfers: see [Approvals](../04-products/05-payouts.md#approvals).
- [ ] **NGN:** Multigate has set up your **remittance collection account**. Without it, NGN remittances are accepted, then fail with "Unable to process remittance transaction".
- [ ] An active NGN account of **your own business** (remittances can't be sent for a customer), funded for the amounts plus fees.

## Build plan

<Steps>
<Step title="Pre-fund your account">

Find your NGN account with [List accounts](api:listAccounts) and note its account number (the wallet's own number or one of its `fundingDetails[].accountNumber` values). Fund it by bank transfer to that number. In the sandbox, use [Simulate an inflow](api:simulateInflow).

Before each remittance, you can check that the balance covers the amount plus the fee with [Get an account balance](api:getAccountBalance) and [Get a transfer fee](api:getTransferFee).

</Step>
<Step title="Check the beneficiary's account">

A remittance doesn't check the beneficiary's account for you, so a wrong number or name is only caught by the bank. Call [Look up an account name](api:nameEnquiry) for every new beneficiary, with the bank code from [List banks](api:listBanks):

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

The answer is HTTP `200` even when the account isn't found: only `responseCode` `00` means found. Show `bankAccountName` to your sender to confirm before you pay. Nigerian account numbers (NUBAN) are exactly 10 digits.

</Step>
<Step title="Send the remittance">

Generate a `uniqueRequestId` (your unique ID for this remittance, unique across all of Multigate: use a UUID or your own prefix), **store it**, then call [Initiate a remittance](api:createRemittance):

```bash
curl -X POST "$MG_BASE_URL/payment-service/api/v1/transfer/remittance" \
  -H "mp-api-key: $MG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "uniqueRequestId": "acme_rm_20261010_0001",
    "sourceAccountNumber": "1029384756",
    "currencyIso3Code": "NGN",
    "amount": 180000,
    "narration": "Family support Oct",
    "sender": {
      "firstName": "John", "lastName": "Mensah",
      "emailAddress": "john.mensah@example.com", "phoneNumber": "+447700900123",
      "address": "10 High Street", "city": "London", "countryIso3Code": "GBR"
    },
    "beneficiary": {
      "firstName": "Ama", "lastName": "Mensah",
      "accountName": "AMA MENSAH", "accountNumber": "0123456789",
      "bankBicOrCode": "058", "bankName": "Guaranty Trust Bank", "countryIso3Code": "NGA"
    }
  }'
```

- The currency field is `currencyIso3Code` here (a transfer uses `sourceCurrencyIso3Code`).
- Send every sender detail you hold, and `sender.bvn` (Bank Verification Number) for Nigerian senders: they're used for compliance screening.
- Use `accountName` as the bank returned it in the previous step.
- The response is nested under **`data`**. Store `data.transactionId` (`PMT-…`) with your `uniqueRequestId`.

Field rules and errors: [Remittance](../04-products/07-remittance.md).

</Step>
<Step title="Handle the outcome">

Wait for [`transfer` / `transfer_completed`](webhook:transfer.transfer_completed) or [`transfer_failed`](webhook:transfer.transfer_failed), matched by `uniqueRequestId`, then notify the sender.

Some outcomes send no webhook (an approver's decline, a compliance decline), so poll [Get a remittance](api:getRemittance) with your `uniqueRequestId` or the `transactionId` for remittances that stay non-final. `data.failureReason` explains a `failed` one.

On failure, either refund your sender in your own system, or fix the details and send a **new** remittance with a **new** `uniqueRequestId`.

If the create call times out or returns `5xx`, the outcome is unknown: look the remittance up with [Get a remittance](api:getRemittance) before doing anything else, and retry only with the **same** `uniqueRequestId`. See [Idempotency](../02-concepts/03-idempotency.md).

</Step>
</Steps>

## Statuses

| `data.status` | Final | What to tell the sender |
|---|---|---|
| `pending` | No | Processing (being screened). |
| `pending_approval` | No | Processing (waiting for an approver in your business). |
| `processing` | No | Processing (sent for payment). |
| `completed` | Yes | Paid. |
| `failed` | Yes | Not paid; any debit is reversed. Read `failureReason`. |
| `rejected` | Yes | Not paid; declined by your approver. |

See [Transfer statuses](../04-products/05-payouts.md#transfer-statuses) for the `responseCode` behind each.

## Data to store

| Field | From | Used for |
|---|---|---|
| `uniqueRequestId` (stored **before** the call) | your own | Lookups after a timeout, matching webhooks |
| `data.transactionId` (`PMT-…`) | [Initiate a remittance](api:createRemittance) | Support, statements, receipts |
| Sender and beneficiary details, and the name enquiry result | your app, [Look up an account name](api:nameEnquiry) | Compliance records |
| Final status, `responseMessage` or `failureReason` | webhook or [Get a remittance](api:getRemittance) | Notifying the sender |

## Webhooks to handle

| Event | What to do |
|---|---|
| [`transfer` / `transfer_completed`](webhook:transfer.transfer_completed) | Mark paid; notify the sender. |
| [`transfer` / `transfer_failed`](webhook:transfer.transfer_failed) | Mark failed; show the reason; refund or resend with a new ID. |

Remittances send no "Transfer Notification" emails; only "Transaction Declined" if an approver declines one. See [Outcomes without a webhook](../03-webhooks-and-emails/02-event-catalogue.md#outcomes-without-a-webhook).

## Reconciliation

Each day, pull yesterday's [Get an account statement](api:getAccountStatement) for your funding account. Match each debit to a remittance by `customReference` (your `uniqueRequestId`), account for `Fee` lines, and compare `closingBalance` with your own records. Remittances also appear in [Find transfers](api:listTransfers). See [Balances and statements](../04-products/10-balances-and-statements.md#daily-reconciliation).

## Go-live notes

- Ask Multigate to set up your production remittance collection account before your first NGN remittance.
- Agree your approval rules: a remittance waiting for an approver stays `pending_approval`.
- Keep each remittance within the per-payment maximum ([List payment methods](api:listPaymentMethods)): remittances are never split. Send several, each with its own `uniqueRequestId`.
- Plan for local-currency payouts: USD remittances to a third party are refused today, because the endpoint can't take supporting documents.
- Keep sender data complete; it's used for compliance screening.
- Work through the [go-live checklist](../01-get-started/07-go-live-checklist.md).
