Skip to main content
POST
Pay a Bill

Overview

Pays a single bill from a READY discovery. You choose one billId out of that transaction’s bills[]; the same transaction then carries the payment through to a final state.
200 is an acknowledgement, not an outcome. It means the payment was accepted and is now in flight. Whether the money actually moved is only knowable from the transaction’s status — poll until it reaches SUCCESS, FAILED or REFUNDED.
This is the call that moves money. Everything you need on your own side — the order record, the amount, your customer’s authorisation — should already be persisted before you send it.

Request Body

string
required
The discovery to pay against. Must be a 24-character lowercase hexadecimal string, and the transaction must currently be READY.
string
required
The billId of one entry in that transaction’s bills[]. Maximum 100 characters.Copy it from the response — do not construct it.
string
required
A new reference for this payment. Maximum 100 characters, and unique among your live transactions for that partner.It must be different from the ref you used for the discovery; reusing that value answers 403 DUPLICATED_REF.
The transaction keeps the ref it was created with. That original discovery ref is what this endpoint echoes back, what Get Transaction by Reference looks up, and what appears on the transaction from now on.

Response

boolean
required
true when the payment was accepted.
object
required
object
required
string
required
Correlation identifier, also sent as the X-Request-Id response header.

Examples

Success Response

Once the transaction reaches SUCCESS, Get Transaction by ID returns operationId and receiptUrl alongside selectedBill and total.

Error Responses

The body did not match the schema.
Common causes: a transactionId that is not 24 hexadecimal characters, a missing billId, a missing ref, or a ref longer than 100 characters.What to do: fix the request. Never retry it unchanged.
The key was absent or rejected.
What to do: verify the key with Validate API Key. Nothing was charged.
The ref is already in use for this partner.
The most common cause is reusing the discovery ref on the payment. Send a distinct value, for example pay- in front of your order identifier.What to do: before retrying, check the transaction’s current state with Get Transaction by ID. If it is already PROCESSING, your payment went through and there is nothing to resend.
The transaction does not exist for your account, or it is not in a payable state, or that billId is not one of its bills.
All three cases answer 404 — including a transaction that belongs to another partner, so the API never confirms that someone else’s transaction exists.What to do: re-read the transaction. If its status is no longer READY, the payment has already been started; poll it instead of sending another one.
This exact bill was already paid.
What to do: treat it as a successful outcome that you already have. Find the paid transaction in List Transactions and use its receipt. Do not charge your customer twice.
Another payment for the same bill has not finished.
What to do: poll the transaction that is already running. Sending this again will not make it finish sooner.
The biller cannot be reached, or is currently switched off.
What to do: nothing was charged. The discovery is still READY, so you can pay the same billId again later — with the same ref, which was never consumed.
We could not verify your key in time. Your key is not the problem.
What to do: wait for Retry-After (5 seconds) and retry the same request. The request never reached the payment path, so retrying it is safe.
The Bill Payment API is in planned maintenance.
What to do: honour Retry-After and retry.
Something failed on our side.
What to do: do not resend the payment. Read the transaction first — if it is PROCESSING, the payment is running. Contact support with the requestId if the state is unclear.

What you pay

Every bill in a discovery carries its own money fields. The fee is a percentage of the amount, clamped between a minimum and a maximum, set per biller: Because 0.5% of a typical bill is well under the minimum, most payments are charged exactly the minimum. These rates are configuration and can be adjusted, so read fee from the response rather than recomputing it. total appears on the transaction once a bill has been selected. For the 443.39 DZD ADE bill above: 0.5% is 2.22, which is below the 30 DZD minimum, so fee is 30.00 and total is 473.39.

Before you call

1

Persist your own record first

Write your order — customer, transactionId, billId, amount, fee, total and the ref you are about to use — before the request leaves your process. If the response is lost, that record is how you find the payment again.
2

Confirm the amount with your customer

amount and fee come from the discovery. Show the total you are about to charge, not an estimate.
3

Send the payment

One call, with a ref that is new for this partner.
4

Poll until final

SUCCESS, FAILED or REFUNDED. Treat UNKNOWN as “keep polling”, never as a failure.Status polling

The guards that protect you

Three rules stop the same money moving twice. All three answer before anything is charged.
None of these three is a reason to retry with a different ref. Each one means the work either is already done or is already running — look it up rather than sending it again.

Best Practices

Write before you send

Persist your order record, including the ref, before the request. A lost response is then recoverable.

One ref per call

Use a distinct ref for the discovery and for the payment. disc- and pay- in front of your order identifier is enough.

Never resend on a timeout

Read the transaction first. A network timeout does not mean the payment did not happen.

Charge from total

Debit your customer the total the API returned, never a figure you calculated yourself.

Discover Bills

Find what is payable

Get Transaction by ID

Poll the outcome

Download Receipt

Proof of payment

Get Transaction by Reference

Recover a lost response

Paying Bills

The full walkthrough

Status Polling

A production-grade poller