Confirming a payment
Two independent signals. Use both, and never credit on the redirect alone.
#The redirect tells you what to ask about
redirect_url on POST /payments is shown as a return link on the success page. From 30 Aug 2026 it carries reference:
https://acme.ng/thanks -> https://acme.ng/thanks?reference=CHK123
https://acme.ng/thanks?order=A17 -> https://acme.ng/thanks?order=A17&reference=CHK123It used to be rendered bare, which made it useless for the thing a redirect is for: your page had no way to know which payment had completed, so it could not confirm anything and had to either trust a webhook that may not have landed yet, or rely on a session of its own, which fails the moment a payer finishes on a different device from the one they started on.
Your own query string is preserved, and a reference you set yourself is not overwritten. https only: anything else is dropped rather than rendered.
#Then confirm it server side
Never credit on the redirect alone. It is a URL in a browser: anybody can type it. It tells you which payment to ask about, nothing more.
GET /v1/payments/CHK123
Authorization: Bearer sk_live_…Scoped to your own merchant and mode, so a reference from anywhere else is 404 not_found rather than readable. Credit on what this returns, never on what the browser said.
#And still take the webhook
collection.success is the signal that arrives whether or not the payer ever comes back to your site, which on a bank transfer is common: they finish in their banking app and close the tab. A shop that only credits on redirect loses those customers silently.
The two carry the same reference, so handling both and de-duplicating on it is the whole integration:
| Redirect | Webhook | |
|---|---|---|
| Arrives | as soon as the payer clicks back | when the money lands |
| Reliable | no, the payer may never return | yes, retried |
| Trustworthy | no, confirm it | yes, signed |
| Use it to | know what to ask about | credit |
Test both with the outcomes in Test mode: making a payment happen.
The signature recipe and the retry schedule are on webhooks. Both outcomes are testable end to end with test mode.