Docs

Success & Cancel Redirects

Return customers safely without confusing navigation with settlement.

Configure success and cancel URLs in project settings. In production they must use HTTPS and their hostnames must be listed exactly in allowedRedirectDomains.

For v2 sessions, checkout adds sessionId and status. The following invoice-specific examples describe v1. Checkout adds two query parameters to both return URLs: invoiceId (the BramaPay invoice ID) and status (the last invoice status received from the API, in lowercase). These names are reserved: existing values, including duplicate values, are replaced. Other query parameters are preserved; their URL encoding may be normalized.

  • paid: automatic navigation to successUrl after the API reports PAID.
  • pending: manual navigation to cancelUrl while the invoice is still pending. Leaving checkout does not cancel it.
  • expired: manual navigation to cancelUrl after the API reports EXPIRED.
  • cancelled: manual navigation to cancelUrl after the API reports CANCELLED.
  • underpaid or overpaid: manual navigation to cancelUrl; the payment needs review.

For example, https://shop.example/payment/success?source=checkout becomes https://shop.example/payment/success?source=checkout&invoiceId=INVOICE_ID&status=paid. The return URL https://shop.example/payment/return?source=checkout becomes https://shop.example/payment/return?source=checkout&invoiceId=INVOICE_ID&status=expired for an expired invoice.

Only a paid invoice redirects automatically. For other statuses, the customer clicks "Return to store". Expiry does not trigger an automatic redirect because a transfer sent before the deadline may still be confirmed. A local countdown reaching zero does not change the API status. Return navigation never cancels an invoice or an on-chain transfer.

URLs are saved on each invoice when it is created. Changing project settings affects new invoices only. If a saved return URL is absent, checkout does not invent a destination.

Store the invoice ID alongside your order ID (externalId) when creating an invoice. On return, resolve that association on your server and check that the invoice belongs to the current customer's order. BramaPay does not automatically append externalId, metadata, amounts, API keys, or signatures to the URL. Do not put secrets or personal data in merchant query parameters.

Success does not mean paid

Treat every redirect and query parameter as untrusted. The browser can alter them, a status can become stale, and a customer may never return. Your backend must independently accept a verified signed webhook or call GET /v1/invoices/:invoiceId, match the stored invoice and order, and require PAID before fulfillment. Process fulfillment idempotently. Show a pending confirmation state if the redirect arrives before your webhook; never mark an order paid or permanently failed from the URL alone.