Skip to content
MultigateAPI
Support Staff

Products

Receivables

A receivable is an invoice you register with Multigate. Each one gets its own virtual account, and every payment into that account is matched to the invoice automatically, including partial payments and overpayments.

When to use it

Use receivables when you issue invoices and want to stop reconciling payments by hand: a payment is matched by the account it was paid into, not by its narration or amount. For general collections, use a regular virtual account.

In short: create the receivable, wait until it has an account, give that account to the payer, and receive a webhook for each payment.

Before you start

  • MG_BASE_URL and MG_API_KEY are set, as in the Quickstart.
  • Set-up by Multigate, per currency: a receivable pool account (where collected money is credited) and a receiving bank that supports receivables. Without them, creating a receivable fails with 400.
  • An active business. Receivables are for your own business; there is no onBehalfOf.
  • An API user with the create receivables permission (can_create_receivables, to create) and view receivables (can_view_receivables, to read and report).
  • A webhook URL, to receive receivables / inflow. See Webhooks.

How it works

sequenceDiagram
    autonumber
    participant You as Your backend
    participant MG as Multigate
    participant Payer
    You->>MG: POST /receivables (invoiceRef, amount, dueDate, uniqueRequestId)
    MG-->>You: 200, status processing, fundingDetails empty
    Note over MG: Account opened in the background
    loop Until status is unpaid or failed
        You->>MG: GET /receivables/{entityId}
        MG-->>You: status, fundingDetails
    end
    You->>Payer: Invoice with the account in fundingDetails
    Payer->>MG: Pays (one or several transfers)
    MG-)You: receivables / inflow (invoice status, amountPaid)
    MG-)You: account / inflow and a Payment Received email
Create the receivable

Generate a UUID for uniqueRequestId and store it with your invoice, then create the receivable:

export MG_REQUEST_ID=$(uuidgen | tr 'A-Z' 'a-z')
curl -s -X POST "$MG_BASE_URL/client-service/api/v1/receivables" \
  -H "mp-api-key: $MG_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "invoiceRef": "INV-2026-0042",
  "amount": 500000,
  "currencyIso3Code": "NGN",
  "payer": "Kola Stores Ltd",
  "issueDate": "2026-10-01",
  "dueDate": "2026-10-31",
  "uniqueRequestId": "$MG_REQUEST_ID"
}
EOF
{
  "message": "Receivable created successfully",
  "entityId": "Rc7mT2qL9xV4nB8kD1sFa",
  "invoiceRef": "INV-2026-0042",
  "amount": 500000,
  "amountPaid": 0,
  "currencyIso3Code": "NGN",
  "payer": "Kola Stores Ltd",
  "issueDate": "2026-10-01T00:00:00.000Z",
  "dueDate": "2026-10-31T00:00:00.000Z",
  "paidDate": null,
  "uniqueRequestId": "4f6a0e1c-2b3d-4e5f-8a9b-0c1d2e3f4a5b",
  "status": "processing",
  "fundingDetails": []
}
  • amount is in major units (500000 is 500,000.00 NGN), stored with 2 decimal places.
  • issueDate defaults to today (UTC). dueDate can't be earlier than issueDate.
  • uniqueRequestId must be a UUID that no other receivable on Multigate has used. A reused ID is refused with 400 and the original isn't returned, so store entityId from the first response.
  • Store entityId (here Rc7mT2qL9xV4nB8kD1sFa): it's the receivable's ID for every later call. Put it in MG_RECEIVABLE_ID for the next step.
Wait for the account

Poll Get a receivable, for example every 10 seconds for a few minutes, until status is unpaid or failed. No receivables webhook is sent for either outcome.

for i in $(seq 1 30); do
  STATUS=$(curl -s "$MG_BASE_URL/client-service/api/v1/receivables/$MG_RECEIVABLE_ID" \
    -H "mp-api-key: $MG_API_KEY" | jq -r .status)
  echo "$STATUS"
  [ "$STATUS" != "processing" ] && break
  sleep 10
done

If the bank opens the account after a delay, you also receive an account / account_opened event with accountType: "receivable" and the receivable's uniqueRequestId. Treat it as a hint to poll; it isn't sent when the account opens straight away.

If status becomes failed, the account couldn't be opened. Create a new receivable with a new uniqueRequestId, or contact Multigate if it keeps failing.

Give the payer the account

Once status is unpaid, send the payer the account in fundingDetails (account name, number, bank and codes). Don't share it while status is still processing.

The account name is the receivables account name Multigate configured for you, if any. Otherwise it is the receivable's payer.

For USD, Multigate asks the bank for an account tied to the invoice amount that expires 60 days after dueDate. This stops payers sending less than the invoice and leaving a shortfall that has to be chased or refunded. Depending on the bank, a payment of a different amount, a second payment, or a payment after expiry can be refused, so ask USD payers to pay the exact amount in one transfer. Instalments (partially_paid) are for NGN receivables.

Receive payments

Each payment into the account sends receivables / inflow:

{
  "header": { "notification_type": "receivables", "notification": "inflow", "hash": "5a6b7c8d…" },
  "body": {
    "receivableDetails": {
      "entityId": "Rc7mT2qL9xV4nB8kD1sFa",
      "invoiceRef": "INV-2026-0042",
      "amount": 500000,
      "amountPaid": 200000,
      "currencyIso3Code": "NGN",
      "uniqueRequestId": "4f6a0e1c-2b3d-4e5f-8a9b-0c1d2e3f4a5b",
      "status": "partially_paid",
      "paidDate": null
    },
    "transactionDetails": {
      "transactionId": "IN-261012-0930151234",
      "amount": 200000,
      "senderAccountName": "KOLA STORES LTD",
      "narration": "INV-2026-0042 part",
      "transactionDate": "2026-10-12T09:30:15.000Z"
    }
  }
}

The payload is shortened here; see the event in Webhooks › Events for every field. Match it to your invoice with receivableDetails.entityId or uniqueRequestId, and use transactionDetails.transactionId to ignore a repeated delivery. Get a receivable lists every payment in payments.

How payments are matched

  • By account. Any payment into the receivable's account counts towards that invoice, whatever its narration, sender or amount.
  • Running total. Each payment adds to amountPaid. paid means the total equals amount; overpaid means it's more.
  • Once per inflow. A payment is recorded once, even if Multigate receives the bank's notification twice.
  • Where the money goes. Payments are credited to your receivable pool account for that currency. Collection fees apply as for any other inflow.
  • After paid or overpaid, Multigate closes the account with the bank. A payment that still arrives before the closure takes effect is added to the total and the status becomes overpaid, but that money stays in the receivable's own account instead of your pool account. Contact Multigate to have it moved.

Receivable statuses

stateDiagram-v2
    direction LR
    [*] --> processing: created
    processing --> unpaid: account ready
    processing --> failed: account couldn't be opened
    unpaid --> partially_paid: part paid
    partially_paid --> partially_paid: more paid
    unpaid --> paid: paid in full
    partially_paid --> paid: paid in full
    unpaid --> overpaid: paid more
    partially_paid --> overpaid: paid more
    paid --> overpaid: late extra payment
    paid --> [*]
    overpaid --> [*]
    failed --> [*]
Status Meaning Webhook
processing The account is being opened. None
unpaid Ready: give the payer fundingDetails. None (poll)
partially_paid Some money received; amountPaid is less than amount. receivables / inflow
paid Exactly the invoice amount received. The account is closed. paidDate is set. receivables / inflow
overpaid More than the invoice amount received. The account is closed. receivables / inflow
failed The account couldn't be opened. None (poll)

Webhooks and emails

When Webhook Email
The account opens after a delay account / account_opened (accountType: "receivable") None
The receivable becomes unpaid or failed None None to you
Each payment receivables / inflow, and account / inflow "Payment Received" to your business contact

Receivables aren't reported to any third party.

Reporting

  • List receivables: newest first, filtered by status and currencies. The response has count (items on this page) and totalCount, not the usual paging fields.
  • Get a receivables summary: totals invoiced (by creation date) and collected (by payment date) per currency, for all time or a date range.
  • Get receivables history: the same totals per month, for the current month and the 5 before it.

Errors and recovery

Status Message Cause What to do
400 A receivable with this uniqueRequestId already exists The ID was used before, by you or anyone. Find your receivable with List receivables, or use a new UUID.
400 A receivable pool account must be configured for this currency before creating a receivable account Receivables aren't set up for the currency. Ask Multigate to set it up.
400 No partner configuration found for this currency or integration No receiving bank supports receivables for the currency. Ask Multigate.
400 dueDate must be larger than or equal to {issueDate} The dates are the wrong way round. Fix the dates.
400 uniqueRequestId must be a valid GUID The ID isn't a UUID. Generate a UUID.
400 Client is inactive Your business isn't active. Contact Multigate.
404 Receivable not found Unknown ID, or another business's receivable. Check the entityId.
404 Resource not found Your API user lacks the permission. Ask your administrator for the permission.
500 Something went wrong… Unexpected error, including two simultaneous creates with the same uniqueRequestId. Check with List receivables before retrying with the same ID.

Next steps