Skip to content
MultigateAPI
Support Staff

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, 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_URL and MG_API_KEY set 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

Create a receivable per invoice

Generate a UUID as uniqueRequestId (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 fundingDetails: the account is opened in the background.

If the call times out, look for your uniqueRequestId with List receivables before retrying. A reused ID is refused with 400 and the original isn't returned.

Wait for the invoice's account

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 from fundingDetails (account name, number, bank) on the invoice.
  • 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_opened with accountType receivable and the receivable's uniqueRequestId: treat it as a signal to poll. Never send the invoice while status is still processing.

Process each payment

Every payment sends receivables / inflow, and also account / inflow. Handle the receivables event:

  1. Verify the signature and store the Idempotency-Key.
  2. Skip it if you've already recorded transactionDetails.transactionId.
  3. Find the invoice by receivableDetails.entityId or receivableDetails.uniqueRequestId.
  4. Update it from receivableDetails.status and receivableDetails.amountPaid (the running total).
status Meaning Your action
partially_paid 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.

Handle overpayments and late payments

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").

Report

Data to store

Field From Used for
uniqueRequestId (a UUID, stored before the call) your own Lookups after a timeout, matching account_opened
Receivable entityId Create a receivable Polling, matching webhooks
fundingDetails Get a receivable once unpaid The account on the invoice
status and amountPaid receivables / inflow Invoice state
Each payment's transactionDetails.transactionId (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_opened (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 transactionDetails.transactionId 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.
  • uniqueRequestId must be a UUID ("uniqueRequestId must be a valid GUID" otherwise).
  • 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.