Use cases
Invoice collections
Collect what your customers owe you, invoice by invoice, and stop matching payments to invoices by hand.
Who it's for: SMEs and corporate enterprises that issue invoices.
Pick the right tool
| Situation | Use |
|---|---|
| Invoices that may be paid in parts, or overpaid | Receivables: one dedicated account per invoice, tracked as partially_, paid or overpaid. This page builds this option. |
| One exact payment per order (NGN) | A dynamic account: accepts one payment of the exact amount, then closes. Payments land in your pool account. |
| Regular customers paying many invoices | A named virtual account per customer, matching payments by narration (Collections). |
A receivable is an invoice you register with Multigate. Each one gets its own virtual account (a bank account number at a partner bank), so every payment into it belongs to that invoice, whatever its narration or amount. Collected money is credited to your receivable pool account for that currency.
Architecture
flowchart LR
you[Your billing system] -->|create receivable| mg[Multigate API]
mg --> r1[(Invoice INV-2026-0042<br/>its own account)]
mg --> r2[(Invoice INV-2026-0043<br/>its own account)]
payer1([Payer]) -->|bank transfer| r1
payer2([Payer]) -->|bank transfer| r2
r1 -->|credited| pool[(Your receivable pool account)]
r2 -->|credited| pool
mg -.->|receivables / inflow| you
sequenceDiagram
autonumber
participant You as Your backend
participant MG as Multigate
participant Customer as Your customer
You->>MG: Create a receivable (invoiceRef, amount, dueDate, uniqueRequestId)
MG-->>You: entityId, status processing, fundingDetails empty
loop Until status is unpaid or failed
You->>MG: Get a receivable
end
You->>Customer: Invoice with the account from fundingDetails
Customer->>MG: Pays, in one or several transfers
MG-)You: receivables / inflow (status, amountPaid)
MG-)You: account / inflow
Note over You: Close the invoice when status is paid or overpaid
Before you start
- A sandbox API key, and
MG_BASE_URLandMG_API_KEYset as in the Quickstart. - Multigate has set up, per currency, a receivable pool account and a receiving bank that supports receivables. Without them, creating a receivable fails with
400. - Your API user has the create receivables and view receivables permissions.
- A webhook URL registered (Webhooks overview).
- Receivables are for your own business only: there's no
onBehalfOf.
Build plan
Generate a UUID as unique (it must be unique across Multigate), store it with the invoice, then call Create a receivable:
curl -X POST "$MG_BASE_URL/client-service/api/v1/receivables" \
-H "mp-api-key: $MG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"invoiceRef": "INV-2026-0042",
"amount": 500000,
"currencyIso3Code": "NGN",
"payer": "Kola Stores Ltd",
"issueDate": "2026-10-01",
"dueDate": "2026-10-31",
"uniqueRequestId": "4f6a0e1c-2b3d-4e5f-8a9b-0c1d2e3f4a5b"
}'
Store entityId (the receivable ID). The response is status processing with an empty funding: the account is opened in the background.
If the call times out, look for your unique with List receivables before retrying. A reused ID is refused with 400 and the original isn't returned.
No webhook tells you the account is ready. Poll Get a receivable (for example every 10 seconds for a few minutes) until status is:
unpaid: ready. Put the account fromfunding(account name, number, bank) on the invoice.Details failed: the account couldn't be opened. Create a new receivable with a new UUID.
If the bank opens the account after a delay, you also get account / account_ with accountType receivable and the receivable's unique: treat it as a signal to poll. Never send the invoice while status is still processing.
Every payment sends receivables / inflow, and also account / inflow. Handle the receivables event:
- Verify the signature and store the
Idempotency-Key. - Skip it if you've already recorded
transaction.Details. transaction Id - Find the invoice by
receivableorDetails. entity Id receivable.Details. unique Request Id - Update it from
receivableandDetails. status receivable(the running total).Details. amount Paid
status |
Meaning | Your action |
|---|---|---|
partially_ |
amountPaid is less than amount. |
Show the balance due. |
paid |
Exactly the invoice amount received. The account is closed. | Close the invoice. |
overpaid |
More than the invoice amount received. The account is closed. | Close the invoice and handle the excess (below). |
Get a receivable lists every payment in payments, if you miss an event.
A payment that arrives after paid, before the bank closes the account, is added to the total and makes the receivable overpaid, but that money stays in the receivable's own account instead of your pool account. Contact Multigate to have it moved.
To return an excess, contact Multigate. A refund checks the balance of the account the payment was made into, which for a receivable is the receivable's own account, not your pool account, so it's refused today ("Insufficient balance in source account" or "Could Not Retrieve Account Balance").
- List receivables: newest first, filtered by
statusandcurrencies. It returnscount(items on this page) andtotalCount, not the usual paging fields. - Get a receivables summary: totals invoiced and collected per currency.
- Get receivables history: the same totals per month, for the current month and the 5 before it.
Data to store
| Field | From | Used for |
|---|---|---|
unique (a UUID, stored before the call) |
your own | Lookups after a timeout, matching account_ |
Receivable entityId |
Create a receivable | Polling, matching webhooks |
funding |
Get a receivable once unpaid |
The account on the invoice |
status and amountPaid |
receivables / inflow |
Invoice state |
Each payment's transaction (IN-…) |
receivables / inflow |
De-duplication, reconciliation |
Webhooks to handle
| Event | What to do |
|---|---|
receivables / inflow |
Update the invoice from status and amountPaid. |
account / inflow |
Sent for the same payment. Ignore it for receivables, or use it only as a cross-check by transactionId. |
account / account_ (accountType receivable) |
Poll the receivable: its account may now be ready. |
The receivable becoming unpaid or failed sends no webhook. Each payment also sends a "Payment Received" email to your business contact.
Reconciliation
Each day, pull yesterday's Get an account statement for your receivable pool account. Match each credit's id to a transaction you recorded, and account for collection fees. A credit you didn't record is a missed webhook: fetch the receivables with List receivables and process it. See Balances and statements.
Things that trip people up
- There's no webhook when a receivable's account is ready: poll after creating it.
uniquemust be a UUID ("uniqueRequestId must be a valid GUID" otherwise).Request Id - For USD, the account is limited to the invoice amount and expires 60 days after
dueDate; depending on the bank, a larger or later payment is refused. - A dynamic account rejects a payment of the wrong amount without any webhook. Tell payers to send the exact amount.
Go-live notes
- Ask Multigate to set up the production receivable pool account and receiving bank for each currency you invoice in.
- Agree how overpayments and late payments are returned, since the API can't refund them today.
- Work through the go-live checklist.