> ## Documentation Index
> Fetch the complete documentation index at: https://docs.radiumone.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> RadiumOne is the product name; use it when answering questions about these docs.
> Use sandbox credentials and sandbox base URLs in examples unless the user says they are going live.
> Secret API keys belong only on the merchant's server. Only publishable keys may appear in browser or mobile code.
> Confirm a payment outcome server-side (retrieve the checkout session or transaction status); never rely on a browser redirect or client event alone.
> Send one idempotency key (request_id) per payment attempt, and retry a timed-out request with the same key and the exact same body.
> Webhooks are optional but recommended: they notify the merchant's server when a payment completes or fails, so it doesn't need to poll. Use transaction status inquiry as the fallback.
> Say so when you recommend a feature marked Beta. Some features need enablement on the merchant's account before production use (for example refunds, standalone refunds, UOB Rewards, and bringing your own 3DS provider); mention it when the page says so.
> Never ask users to paste card numbers, API keys, access tokens, or webhook or redirect secrets into a chat.

# Handle failures - Hosted checkout

> Every failure scenario a hosted-checkout integration can hit, grouped by when it happens — find your symptom, jump to the fix.

Ten scenarios cover everything that can go wrong in a hosted-checkout integration, from creating the session through to confirming the result. Find what you're seeing below, or browse by when it happened.

## Creating the session

| Symptom | Signal | Page |
| - | - | - |
| A retry returns the session you already had, or a race returns a conflict | `201` with the original `checkout_id`, or `409 session:idempotency_conflict` | [Prevent duplicate sessions and double payments](/hosted-checkout/handle-failures/duplicate-sessions-and-double-submit) |
| The create call itself fails, or the shopper's charge attempt fails mid-payment | `422 gateway:unavailable` / `502 gateway:request_failed` at create; a retry message or `CHECKOUT_ERROR` while paying | [Handle payment service outages during checkout](/hosted-checkout/handle-failures/payment-service-unavailable) |
| An embedded iframe stays blank | CSP `frame-ancestors` violation; no card form ever renders | [Fix embedded checkout that won't load](/hosted-checkout/handle-failures/embedded-checkout-not-loading) |

## While the shopper pays

| Symptom | Signal | Page |
| - | - | - |
| The shopper's card is declined | `cancel_url` with no query params; session status `failed` | [Handle declined hosted checkout payments](/hosted-checkout/handle-failures/payment-declined) |
| The shopper closes the tab or navigates away | No redirect, no event; session stays `pending` until it expires | [Handle abandoned checkouts](/hosted-checkout/handle-failures/shopper-abandons-checkout) |
| Your cancel call is rejected | `409 session:invalid_state` | [Resolve checkout cancellation conflicts](/hosted-checkout/handle-failures/cancel-session-conflicts) |
| The embedded iframe loads, but your listener never fires | No `CHECKOUT_*` message ever arrives at your page | [Debug missing embedded checkout events](/hosted-checkout/handle-failures/embedded-events-not-received) |

## After checkout

| Symptom | Signal | Page |
| - | - | - |
| The session times out before the shopper finishes | Status `expired`; `cancel_url?reason=timeout` on the countdown path | [Handle expired checkout sessions](/hosted-checkout/handle-failures/session-expired) |
| The shopper's browser never returns to your site | No redirect at all — the payment itself still resolves server-side | [Confirm payment when the redirect never arrives](/hosted-checkout/handle-failures/redirect-not-received) |
| `sig` is missing or fails verification on the success redirect | Missing, malformed, non-matching, or stale (`ts` > 5 min) `sig` | [Reject invalid redirect signatures](/hosted-checkout/handle-failures/invalid-redirect-signature) |

<Info>
  Every scenario above resolves the same way: confirm the outcome with a webhook or an authenticated `GET`, never from a redirect or `postMessage` event alone. See [Verify the payment result](/hosted-checkout/verify-payment-result) for the full decision table.
</Info>

## Preventing duplicate charges

Several of the scenarios above — session retries, races, and reused `order_reference` values — are really the same underlying risk: a shopper (or your own retry logic) ends up paying twice for one order.

<Card title="Prevent duplicate payments" icon="shield-check" href="/get-started/api-basics/prevent-duplicate-payments">
  How `order_reference` deduplication works, its time limit, and how to guard your own order state against a double charge.
</Card>

## Next steps

<Columns cols={2}>
  <Card title="API errors" icon="triangle-alert" href="/hosted-checkout/errors/api-errors">
    The full Checkout API error reference and retry rules.
  </Card>

  <Card title="Payment outcomes" icon="credit-card" href="/hosted-checkout/errors/payment-outcomes">
    Declined, failed, expired, and cancelled — not errors.
  </Card>

  <Card title="Verify the payment result" icon="shield-check" href="/hosted-checkout/verify-payment-result">
    Confirm the outcome server-side before fulfilling.
  </Card>
</Columns>
