A payment starts with an invoice and ends with evidence from the payment provider. Your customer pays on a Roamerwave-hosted page, so your system never handles a wallet PIN or a card.
1. Create a checkout link
Create an invoice (see the quick start), then ask for a checkout session. expiresAt is when the link stops working.
curl https://api.roamerwave.com/v1/invoices/inv_…/checkout-sessions \
-H "Authorization: Bearer rw_test_…" \
-H "Idempotency-Key: order-1042-checkout" \
-H "Content-Type: application/json" \
-d '{ "expiresAt": "2026-10-31T20:59:59Z" }'
The response contains checkoutUrl. It appears in this response only and is not shown again, so store or send it straight away. Send it to your customer by any channel you like.
{
"id": "chk_…",
"checkoutUrl": "https://pay.roamerwave.com/pay/…",
"expiresAt": "2026-10-31T20:59:59Z"
}
Treat the link as a secret for that customer and that invoice. Do not log it or put it in analytics.
2. The customer pays
On the hosted page the customer sees the seller, the amount and what it is for, chooses an enabled wallet, and approves the payment on their phone. Each time they try is one payment attempt with an id starting payatt_.
3. Learn the result
There are two ways, and you can use both.
- Webhooks. Subscribe an endpoint and you receive a signed
payment.succeededevent when the provider confirms a payment. See Verify webhooks. - Reading.
GET /v1/invoices/{invoiceId}returns the invoice withpaymentStatus, andGET /v1/payment-attempts/{attemptId}returns one attempt.
An attempt has a status and a nextAction that says what is safe to do next:
status | Meaning |
|---|---|
created, initiation_queued | The request has been recorded and is being sent to the provider. |
customer_action_required | The customer has been asked to approve on their phone. |
provider_accepted | The provider has the request and has not yet reported a result. |
succeeded | The provider confirmed the payment. |
failed, initiation_rejected, cancelled, expired | The attempt did not complete. |
reversed | A confirmed payment was later reversed. |
unknown | The result could not be confirmed. See below. |
When the result is unknown
Sometimes the provider does not answer, or answers ambiguously, and Roamerwave cannot say whether the customer was charged. The attempt then has the status unknown, and the invoice's paymentStatus is unknown too.
unknown is a real answer, not an error to be retried away:
- It is not
failed. The customer may have paid. Do not tell them to pay again, and do not release goods or cancel service on the strength of it. - It is not
succeeded. Do not fulfil the order yet. - Roamerwave never turns a timeout into a failure. The attempt stays
unknownuntil the provider's own records resolve it, and then it becomessucceededorfailedwith that evidence behind it. - While it is
unknown, Roamerwave refuses to create another payment link for the invoice and sends no payment request or reminder for it, so the customer is not asked to pay a second time.
The correct handling is to wait. Read the attempt again later, or let the payment.succeeded webhook tell you. Check nextAction: wait_for_update means exactly that.
Fulfil only on confirmation
Fulfil an order when the invoice's paymentStatus is succeeded, or when you receive payment.succeeded and have confirmed it by reading the attempt. A browser redirect back to your site only means the customer left the payment page. It is never proof of payment.
Success is not settlement
succeeded says the provider confirmed the customer's payment. Whether it has been matched to the invoice (reconciliationStatus) and whether the funds have been reported as settled to your account (settlementStatus) are separate facts with their own fields.