Skip to main content

External Collections

Some of your customers will pay you through a channel MALIPOPAY is not connected to: a deposit at a bank we have no integration with, cash at your own counter, a cheque. Until you tell us, the collection reference stays open for the full amount, the bank keeps quoting that amount to the next person who presents the number, and your books on MALIPOPAY understate what you have collected.

POST /api/v1/ledger/external-entries records such a payment against one of your collection references. It reduces what is outstanding on that reference and posts the amount in your own books under External Collections. It never touches your MALIPOPAY wallet, your settlement or any fee, because MALIPOPAY did not receive the money.

note

This endpoint is switched on per account. Until MALIPOPAY enables it for you, every call answers 403 with code 3154. Ask your account contact to enable it.

What it does, and does not do​

BehaviourEffect
Reduces the outstanding amount on the referenceYes
Bank bill lookups (CRDB and other bank channels) quote the reduced amountYes
Appears on the reference's breakdown, itemisedYes
Posts to your General Ledger (External Collections against Sales Revenue)Yes
Moves your MALIPOPAY walletNo
Changes your settlementNo
Charges a feeNo
Changes the reference's statusNo. Read coverage and outstanding instead (see below)

Report a payment​

POST /api/v1/ledger/external-entries
apiToken: YOUR_API_KEY
Content-Type: application/json
{
"reference": "ML229470",
"type": "CREDIT",
"amount": 60000,
"externalReference": "TCB-8842119",
"description": "Cash deposit at TCB Mwanza branch",
"reason": "Customer paid at the bank counter",
"source": "TCB",
"paidAt": "2026-09-22T09:14:00Z"
}
FieldRequiredNotes
referenceYesThe MALIPOPAY reference (ML…), or your own reference for the same bill. If your own reference matches more than one open bill you get 409 code 3156; send the MALIPOPAY reference instead.
typeYesCREDIT records money received. DEBIT reverses a credit you reported earlier.
amountYesInteger, in the currency of the collection.
externalReferenceYesYour identifier for the movement, such as the bank transaction id. This is the idempotency key: sending the same one again returns the original entry instead of posting a second.
descriptionYesWhat the payment was. Shown in your ledger.
reasonYesWhy you are recording it. Kept for audit.
sourceNoWhere the money came in, for example TCB, NMB, CASH. Defaults to EXTERNAL.
paidAtNoWhen you received it. Defaults to now.

Response​

201 Created on a new entry. 200 OK with idempotentReplay: true if that externalReference was already posted with the same type and amount.

{
"success": true,
"code": 3150,
"message": "External ledger entry posted successfully",
"data": {
"entryId": "ext_4SkzJJsvYlqHyeq1",
"reference": "ML229470",
"customerReference": "999107GVA4207",
"type": "CREDIT",
"amount": 60000,
"currency": "TZS",
"externalReference": "TCB-8842119",
"source": "TCB",
"journalId": "jrn_4SkzJJs_vYlqHyeq",
"balanceAfter": {
"externalPaid": 60000,
"outstanding": 40000
},
"idempotentReplay": false,
"createdAt": "2026-09-22T09:14:07.412Z"
}
}

balanceAfter.outstanding is what the reference still asks for after this entry. Zero means the bank will now refuse further payments against it.

Reverse a report​

If a payment you reported turns out not to have cleared, post a DEBIT for the amount. A debit can never exceed the total you have reported on that reference, so it can only undo your own entries; it cannot touch money that arrived through MALIPOPAY.

{
"reference": "ML229470",
"type": "DEBIT",
"amount": 60000,
"externalReference": "TCB-8842119",
"description": "Deposit TCB-8842119 was reversed by the bank",
"reason": "Bounced deposit"
}

A debit may reuse the credit's externalReference: the idempotency key includes type, so a DEBIT with the same reference is a different entry from the CREDIT.

Rules​

  • A CREDIT cannot exceed what is outstanding. 422 code 3158.
  • A DEBIT cannot exceed what you have reported. 422 code 3159.
  • A FIXED amount bill takes only the full outstanding. Bank channels refuse a part payment on a fixed bill, so a part credit would leave a remainder nobody could pay. 422 code 3161 tells you the exact amount to send.
  • Fully paid, failed, cancelled and expired bills are refused. 422 code 3160. A DEBIT on a fully paid bill is still accepted: it corrects the books, but it does not reopen the reference.
  • Invoice control numbers are not supported yet. 422 code 3160.
  • Same externalReference, different amount or type: 409 code 3157. Use a new reference for a new movement.

Read it back​

The breakdown endpoint carries the split:

GET /api/v1/payment/breakdown/ML229470
apiToken: YOUR_API_KEY
{
"summary": {
"requested": 100000,
"paid": 0,
"paidViaMalipopay": 0,
"externalPaid": 60000,
"outstanding": 40000,
"currency": "TZS",
"fullyPaid": false,
"coverage": "PARTLY_COVERED"
},
"externalEntries": [
{
"entryId": "ext_4SkzJJsvYlqHyeq1",
"type": "CREDIT",
"amount": 60000,
"externalReference": "TCB-8842119",
"source": "TCB",
"paidAt": "2026-09-22T09:14:00.000Z"
}
]
}
FieldMeaning
paid, paidViaMalipopayMoney that arrived through MALIPOPAY. The same number under both names; paid is kept for older integrations.
externalPaidNet of the credits and debits you have reported.
outstandingrequested - paid - externalPaid, never below zero.
coverageOPEN, PARTLY_COVERED, COVERED (reached zero with at least some MALIPOPAY money) or COVERED_EXTERNALLY (reached zero on your reports alone).

A bill that reaches zero on external reports alone keeps its status (typically PROCESSING or PARTIAL) because no money moved through MALIPOPAY. Bank channels still refuse it. Drive your own logic from outstanding and coverage, not from status.

Two more endpoints, both with apiToken:

  • GET /api/v1/ledger/external-entries?reference=&type=&fromDate=&toDate=&page=&limit= lists what you have reported, newest first.
  • GET /api/v1/ledger/external-entries/summary?fromDate=&toDate= returns platformCollected, externalCredits, externalDebits, externalNet and total for the period, so a settlement conversation can separate what MALIPOPAY holds from what you collected yourself.

Status codes​

HTTPCodeMeaning
2013150Entry posted
2003151Already posted; the original entry is returned
2003152Entries listed
2003153Summary generated
4033154External ledger entries are not enabled for this account
4043155No collection found for that reference
4093156Your reference matches more than one open collection; use the MALIPOPAY reference
4093157That external reference was already used for a different entry
4223158The amount is more than the collection still has outstanding
4223159A debit cannot exceed the external collections reported on this reference
4223160This collection cannot take an external ledger entry
4223161This bill must be paid in full; report the whole outstanding amount

Known limits​

  • A DEBIT after a bill is fully paid corrects your books but does not reopen the reference.
  • A USSD push you re-send on a part-covered reference still asks the customer for the full amount. Bank bill lookups quote the true outstanding.
  • Invoice control numbers are excluded for now.