Skip to content

Day settlements

If you pay a service provider directly — one bank transfer covering a day’s payments — tell UniPay about each transfer. UniPay matches every payment you list against the payments you reported, finds the ones you left out, and tells you at once whether the transfer balances. The service provider sees the same report when it reconciles its bank statement.

Send one day settlement per transfer with POST /api/app/payment-processor/settle-day, scope unipay:bills.

Send it when you make the transfer — usually the business day after the payments were taken.

  • settlementDate is the day of the transfer. UniPay reconciles it against your payments dated the day before, in your business timezone (normally Africa/Harare).
  • One settlement is one transfer, to one service provider, in one currency. If you pay a provider in two currencies, or pay two providers, send one settlement for each transfer.
  • List every payment the transfer covers, by its rrn.
sequenceDiagram
    participant PP as You
    participant U as UniPay
    participant SP as Service provider
    Note over PP,U: Day 1: payments reported as usual
    PP->>SP: Day 2: bank transfer for day 1
    PP->>U: settle-day (transfer reference, every rrn)
    U-->>PP: Matched, differences, balanced?
    SP->>U: Read the processor settlements feed
    U-->>SP: Your transfer, line by line
{
"settlementDate": "2026-09-30",
"transferReference": "RTGS20260930-0042",
"billerCode": "4444",
"creditedAccountNumber": "1234567890",
"currency": "USD",
"totalAmount": 368.50,
"feeAmount": 1.50,
"lines": [
{ "rrn": "PX20260929000123", "billNo": "4444INV0009", "amount": 170.00 },
{ "rrn": "PX20260929000124", "amount": 200.00 }
]
}
Terminal window
curl -X POST https://test.unipay.co.zw/api/app/payment-processor/settle-day \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @settlement.json
Field Required Rules
settlementDate Yes The day of the transfer, yyyy-MM-dd. Not in the future and not more than 90 days ago. A date-time is accepted, but only its date is used, exactly as written — the time and offset are ignored.
transferReference Yes Your bank or RTGS reference for the transfer, up to 100 characters. It makes the request safe to retry.
billerCode Recommended The service provider paid: its number or short code, up to 64 characters. Every rrn must then be one of its payments.
creditedAccountNumber Recommended The provider’s bank account you credited, up to 64 characters. Providers bank with several banks and can’t otherwise tell which account received the money.
currency Yes Three-letter ISO 4217 code of the transfer.
totalAmount Yes What you transferred: the sum of the lines less feeAmount. Greater than zero.
feeAmount Commission you kept from the transfer, if any. Default 0. Must be less than the sum of the lines.
lines Yes 1 to 5,000 lines, one per payment.
lines[].rrn Yes The payment’s rrn, as you reported it. Up to 50 characters, each at most once.
lines[].amount Yes The amount of that payment. Greater than zero.
lines[].billNo The bill paid, up to 100 characters. When you send it, it must be the bill UniPay recorded; spaces, dashes and case don’t matter.

Without billerCode, UniPay takes the provider from the payments you list. Send it anyway: if none of the rrns is recognised, a settlement with no provider isn’t shown to anyone but you. An account number UniPay doesn’t recognise is recorded as you sent it and flagged to Axis for checking; it doesn’t refuse the settlement, because the money has already moved.

"successful": true means UniPay recorded and reconciled the settlement — not that it balanced. Check isBalanced.

{
"successful": true,
"message": "Settlement accepted with 2 difference(s).",
"isNewRecord": true,
"settlementId": "3a24048c-e7c8-c3bc-e816-72a95370cb3b",
"settlementDate": "2026-09-30",
"transferReference": "RTGS20260930-0042",
"currency": "USD",
"reconDate": "2026-09-29T00:00:00Z",
"reconTimeZone": "Africa/Harare",
"reconWindowStartUtc": "2026-09-28T22:00:00Z",
"reconWindowEndUtc": "2026-09-29T22:00:00Z",
"reportedTotal": 370.00,
"feeAmount": 1.50,
"transferredAmount": 368.50,
"matchedTotal": 170.00,
"reportedCount": 2,
"matchedCount": 1,
"unmatchedByUnipay": [
{ "rrn": "PX20260929000124", "billNo": null, "amount": 200.00, "unipayAmount": 150.00, "reason": "AmountMismatch" }
],
"unsettledByProcessor": [
{ "rrn": "PX20260929000131", "billNo": "4444INV0011", "amount": 40.00, "unipayAmount": 40.00, "reason": "NotSettledByProcessor" }
],
"difference": 10.00,
"isBalanced": false
}
Field Meaning
settlementId UniPay’s ID for the settlement. Store it to read it back.
reconDate The day whose payments were reconciled — the day before settlementDate. Only the date part means anything.
reconTimeZone, reconWindowStartUtc, reconWindowEndUtc That day as a UTC window: payments with a paymentDate inside it were expected.
reportedTotal, reportedCount The sum and count of your lines, before commission.
feeAmount, transferredAmount As you sent them. transferredAmount is your totalAmount.
matchedTotal, matchedCount The lines that matched a payment exactly.
unmatchedByUnipay Your lines that didn’t match, each with a reason. amount is yours; unipayAmount is what UniPay recorded, when it found the payment.
unsettledByProcessor Payments you reported for that day, to that provider and in that currency, that the settlement left out.
difference reportedTotal less what UniPay holds as owed — its own amount for every payment you listed that it counts, plus the ones you left out. Negative: you sent less.
isBalanced true only when every line matched and nothing was left out. Differences can cancel out, so a zero difference alone doesn’t mean balanced.

The message is Settlement balanced — all payments matched. when it balances, otherwise Settlement accepted with N difference(s).

reason Meaning Counted as owed?
UnknownRrn You reported no payment with this rrn. No
AmountMismatch The payment exists, with a different amount. Yes, at UniPay’s amount
BillMismatch The payment exists, against a different bill from the billNo you sent. Yes
CurrencyMismatch The payment was made in a different currency from the transfer. No
Reversed The payment has been reversed: there’s nothing to settle. No
AlreadySettled An earlier settlement already matched this payment. No
NotSettledByProcessor In unsettledByProcessor: a payment for that day you left out. Yes

A payment counts as settled once a line matches it. So if you left a payment out, or reported the wrong amount, include it in a later transfer: that settlement matches it and clears the earlier difference. Include a matched payment again and it comes back AlreadySettled. New reasons may be added; treat one you don’t recognise as a difference.

Every difference is also raised with Axis operations. Once you use day settlements, Axis is also alerted when a day on which you took payments gets no settlement.

A settlement UniPay can’t accept answers HTTP 200 with "successful": false. Nothing is recorded; fix the request and send it again — you can reuse the transferReference.

message Cause
Settlement date is required · Settlement date cannot be in the future · Settlement date cannot be more than 90 days in the past Check settlementDate.
Total amount must be greater than zero · Fee amount cannot be negative Fix the amount.
Total amount X does not equal the sum of the lines Y With no fee, totalAmount must be the sum of the lines.
Total amount X does not equal the sum of the lines Y less the fee Z totalAmount must be the sum of the lines less feeAmount.
Fee amount X must be less than the sum of the lines Y Fix feeAmount.
Currency must be 3 characters Fix currency.
Transfer reference is required · Transfer reference must not exceed 100 characters Fix transferReference.
Credited account number must not exceed 64 characters · Biller code must not exceed 64 characters Fix the field.
At least one line is required · A settlement may contain at most 5000 lines Fix lines.
Every line needs an RRN · RRN 'X' must not exceed 50 characters · RRN 'X' appears more than once Fix the line.
Amount for RRN 'X' must be greater than zero · Bill number for RRN 'X' must not exceed 100 characters Fix the line.
Biller 'X' not found · Biller code 'X' is ambiguous; use the service provider number Fix billerCode.
Every RRN in the settlement must belong to biller 'X'. A payment you listed was made to another provider.
The RRNs belong to N service providers. A settlement covers one biller's transfer; submit one per biller. Split the settlement by provider.
Transfer reference 'X' was already submitted with a different date, currency or total. See Retrying.

A settlementDate that isn’t a date at all — 30/09/2026, say — gets HTTP 400, with the message '30/09/2026' is not a date. Use yyyy-MM-dd, for example "2025-01-17".

The transferReference identifies the settlement. If a call times out, or you get a 429 or 5xx, send the same request again:

  • Same reference, same settlementDate, currency and totalAmount: you get the recorded result again, with isNewRecord: false. The lines aren’t compared — the answer is always the first one recorded.
  • Same reference with a different date, currency or total: refused, because that’s a different transfer or a mistake.

A settlement can’t be changed once recorded. If a transfer was wrong, correct it with your next transfer — the payments it matches are cleared as above. The general policy is in Idempotency and retries.

Read a settlement again at any time, for example to recover an answer you lost. Both endpoints answer in the same shape as settle-day, with isNewRecord: false, and only ever show your own settlements.

Call Returns
GET /api/app/payment-processor/{id}/day-settlement One settlement, by settlementId. An unknown ID gets 404.
GET /api/app/payment-processor/day-settlements Your settlements, newest settlementDate first, as { "totalCount": …, "items": [ … ] }.

The list takes from and to (settlement dates, yyyy-MM-dd, inclusive, both optional), skipCount, and maxResultCount — 20 by default, at most 100. A from after to is refused with the error object.

Your administrators also see every settlement and its differences in the UniPay portal, under My settlements.

The provider reads your settlement from its processor settlements feed: your transfer reference, the account you credited and whether it recognises it, gross, fee and net amounts, whether it balanced, and every line with its outcome — including the payments you left out.

UniPay API v1 · build e1eb5c49 · Powered by Axis Solutions