How to handle pending bill payment API transactions
Keep pending bill payments recoverable with stored references, status checks and webhook reconciliation. Avoid charging or purchasing again after a timeout.
Already registered? Open API settings and follow the business-access steps. Sandbox purchases do not deliver real services.
Reviewed
A customer presses Pay, the request takes longer than expected, and the app has no result to show. This is the point where a payment integration needs a recovery path. A timeout describes what your server observed; it does not establish whether the purchase reached RizPay or the biller.
Separate acceptance from completion
The purchase endpoint can return an accepted transaction whose status is pending. Save data.id and data.attributes.status with your local order. Keep the original external reference, the customer-confirmed product and the amount you collected. Your order page should retrieve that same record on every refresh.
Use a status view such as "We are checking your purchase. You can leave this page and return to this order." State only the money status your own ledger supports. If you collected a payment, do not claim it was refunded unless the refund record exists.
Decide what to do from evidence
| Situation | Next action |
|---|---|
| You have a transaction ID and it is pending | Retrieve that transaction; keep the order unresolved. |
| You lost the create response but have your reference | Look up the reference in account transactions. |
| A webhook arrives for the order | Verify it, deduplicate the event and reconcile the stored transaction. |
| The API returns successful | Record fulfillment and make the receipt available. |
| The API returns failed or reversed | Reconcile the purchase and your customer's payment separately. |
| The response is missing or unrecognized | Preserve the unresolved order and investigate. |
For a known transaction, GET /purchases/:id reads its current state. The documented POST /purchases/:id/query requests a requery for a pending transaction; it is not a new purchase and its response need not be final. Use bounded polling and respect rate-limit headers. A short loop in a customer browser is not a reconciliation worker.
Make recovery survive a restart
Save the order before making the purchase request. A background worker should be able to find unresolved orders after a deployment or process crash. Record when you last checked and limit repeated checks so one stuck order cannot consume every available API request.
If the original response was lost, read /account/transactions/ followed by the stored reference. That path resolves an external reference directly, so verify that the returned record belongs to the intended order. If you still cannot establish the outcome, escalate with the existing reference rather than generating a new purchase.
Plan for late events
A late pending event must not overwrite a newer successful state. A reversal can legitimately follow a success and needs its own financial handling. When events disagree or arrive out of order, retrieve the current transaction and reconcile it under a local order lock.
The receiver should acknowledge an event only after it has been durably accepted for processing. Receipt delivery can be retried independently; sending another receipt must never create another purchase.
Test the pending-to-success and pending-to-failure sandbox scenarios before enabling production. Check both a customer refresh and a worker restart while the order is pending.