> ## 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.

# Architecture - Hosted checkout

> Where hosted checkout sits between the shopper, your site and server, and RadiumOne — and why it keeps your PCI scope minimal.

export const DataFlow = ({letter, from, to, twoWay, children}) => <div className="r1-flow" role="listitem">
    <span className="r1-flow__badge" aria-hidden="true">{letter}</span>
    <div className="r1-flow__content">
      <div className="r1-flow__title">
        <span className="r1-flow__sr-only">{`Flow ${letter}: `}</span>
        {from}
        <span className="r1-flow__arrow" aria-hidden="true">
          <Icon icon={twoWay ? "arrow-left-right" : "arrow-right"} size={14} />
        </span>
        <span className="r1-flow__sr-only">{twoWay ? " and back to " : " to "}</span>
        {to}
      </div>
      <div className="r1-flow__body">{children}</div>
    </div>
  </div>;

export const DataFlows = ({children}) => <div className="r1-flows" role="list">
    {children}
  </div>;

Hosted checkout is built from four pieces: the shopper's browser, your website and server, RadiumOne Checkout (the hosted payment page), and the RadiumOne Payments API behind it. Your server only ever talks to RadiumOne over server-to-server calls and webhooks — the shopper's card details never pass through your website or server at all.

## Where it sits

### Components

* **Your website** — runs in the shopper's browser; sends the shopper to RadiumOne Checkout and reacts to the return.
* **Your server** — holds your secret key and your webhook endpoint; the only part of your stack that talks to RadiumOne directly.
* **RadiumOne Checkout** — the hosted payment page plus the Checkout API, where the shopper enters their card.
* **Payments API** — the gateway that actually charges the card once RadiumOne Checkout submits it.
* **Card networks & issuer** — resolve the authorization request.

### Data flows

The letters match the flow tags in the diagram.

<DataFlows>
  <DataFlow letter="A" from="Your server" to="RadiumOne Checkout">
    Your server creates a checkout session with [`POST /api/v1/checkout/sessions`](/hosted-checkout/reference/checkout-sessions/create-a-checkout-session), authenticated with your secret key.
  </DataFlow>

  <DataFlow letter="B" from="Your website" to="RadiumOne Checkout">
    Your website sends the shopper to the payment page — by redirecting to `checkout_url`, or by showing it in an iframe. See [Redirect vs embedded](/hosted-checkout/redirect-vs-embedded).
  </DataFlow>

  <DataFlow letter="C" from="RadiumOne Checkout" to="Payments API">
    When the shopper pays, RadiumOne Checkout charges the card in a single step — a sale, not authorize-then-capture — using one `request_id` per session so it can't charge twice. See [Session lifecycle](/hosted-checkout/session-lifecycle).
  </DataFlow>

  <DataFlow letter="D" from="Payments API" to="Card networks & issuer">
    The card network and the shopper's bank approve or decline the payment.
  </DataFlow>

  <DataFlow letter="E" from="RadiumOne Checkout" to="Your website">
    The shopper comes back to your site: a redirect, or a `postMessage` event in embedded mode. Use it to update your page, but treat it as a **hint only**, never proof of payment.
  </DataFlow>

  <DataFlow letter="F" from="Payments API" to="Your server">
    A signed webhook tells your server the final outcome, such as `payment.captured`. It arrives asynchronously and is the source of truth.
  </DataFlow>

  <DataFlow letter="G" from="Your server" to="RadiumOne Checkout">
    Your server can also retrieve the session to confirm the result on its own, without relying on the redirect or the webhook.
  </DataFlow>
</DataFlows>

## PCI scope: card data never reaches you

With hosted checkout, the shopper enters their card details on a RadiumOne-hosted page. Your server and website never see or handle raw card data, which keeps your PCI DSS scope minimal.

The card fields render inside RadiumOne Checkout, and the browser sends the card data straight to RadiumOne — it's never proxied through your server, and your website's own code never touches it either. That's what keeps card entry outside your systems entirely, and it's the main architectural difference from [Elements](/elements/overview), where card fields render on *your* page (still tokenized in the browser, never touching your server).

## Trust boundaries

Three mechanisms keep the pieces above honest about who can claim a payment succeeded:

<Steps>
  <Step title="The redirect is a hint, never proof">
    A redirect back to your `success_url` (or a `postMessage` event in embedded mode) can carry a `sig` — an HMAC over the outcome, signed with your redirect secret. Even signed, treat it as a **UI signal**: confirm the actual result with an authenticated request or a webhook before you fulfil anything. See [Verify the payment result](/hosted-checkout/verify-payment-result) for the signature format and the full decision table.
  </Step>

  <Step title="Webhooks are the source of truth">
    RadiumOne delivers `payment.*` webhook events for every terminal outcome, signed and retried on your behalf. Your server should treat a verified webhook (or an authenticated `GET` on the session) as the only basis for shipping an order — see [Webhooks](/payments-api/webhooks/overview).
  </Step>

  <Step title="Your secret key never leaves your server">
    Session creation is the one call your server makes directly to RadiumOne, authenticated with your secret key.

    <Danger>
      Never use a secret key (`r1sk_…`) in browser code, mobile apps, or anywhere a shopper can inspect it. Secret keys belong on your server only.
    </Danger>
  </Step>
</Steps>

## Next steps

<Columns cols={2}>
  <Card title="Redirect vs embedded" icon="git-compare" href="/hosted-checkout/redirect-vs-embedded">
    Compare the two integration modes and how to choose between them.
  </Card>

  <Card title="Redirect to hosted checkout" icon="arrow-right" href="/hosted-checkout/redirect-integration">
    Build the simplest integration: create a session and redirect the shopper.
  </Card>

  <Card title="Embed hosted checkout" icon="panel-top" href="/hosted-checkout/embedded-integration">
    Keep the shopper on your domain with an iframe.
  </Card>

  <Card title="Verify the payment result" icon="shield-check" href="/hosted-checkout/verify-payment-result">
    The signature format and the server-side confirmation decision table.
  </Card>
</Columns>
