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

# Sandbox and API keys - Get started

> Set up a sandbox account, understand RadiumOne's key types and scopes, and request least-privilege credentials before you go live.

export const productionCdnHost = "https://js.radiumone.io";

export const sandboxCdnHost = "https://js-sandbox.radiumone.io";

export const productionCheckoutHost = "https://checkout.radiumone.io";

export const sandboxCheckoutHost = "https://checkout-sandbox.radiumone.io";

export const productionApiBaseUrl = "https://api.radiumone.io/gateway";

export const sandboxApiBaseUrl = "https://api-sandbox.radiumone.io/gateway";

Every RadiumOne integration starts with a sandbox account and a pair of API keys. This page covers both environments, the key types you'll use, and how to keep your keys safe.

## Environments and hosts

| Environment | Purpose | Keys |
| - | - | - |
| **Sandbox** | Build and test your integration. No real money moves. | `r1pk_test_…` / `r1sk_test_…` |
| **Production** | Accept real payments from shoppers. | `r1pk_prod_…` / `r1sk_prod_…` |

Sandbox and production use separate credentials, hosts and webhook endpoints — see [Sandbox and API keys](/get-started/sandbox-and-api-keys).

| Environment | Payments API base URL | Checkout API host |
| - | - | - |
| Sandbox | <code>{sandboxApiBaseUrl}</code> | <code>{sandboxCheckoutHost}</code> |
| Production | <code>{productionApiBaseUrl}</code> | <code>{productionCheckoutHost}</code> |

The Elements SDK CDN adds one more host per environment: sandbox at <code>{sandboxCdnHost}</code>, production at <code>{productionCdnHost}</code>.

## Sandbox behaviour and limits

Sandbox behaves like production — the same API shapes, statuses, and error codes — but no real money moves and no real card issuer is involved. Use test cards from [Test your integration](/resources/test-your-integration) rather than real card numbers; sandbox tokenizes and processes them the same way production does, so there's no separate "mock" token format to learn.

<Info>
  Sandbox is also the place to test your retry logic. Before you write integration code, read [Prevent duplicate payments](/get-started/api-basics/prevent-duplicate-payments) so your `request_id`/`order_reference` handling is safe from the start.
</Info>

## Key types

| Key type | Prefix | Where it's used |
| - | - | - |
| Secret key | `r1sk_test_…` / `r1sk_prod_…` | Server only. Payments API and Checkout API requests. |
| Publishable key | `r1pk_test_…` / `r1pk_prod_…` / `r1pk_mock_…` | Browser-safe. RadiumOne Elements, hosted-checkout session verification. |
| Access token | opaque token | Bearer token for Payments API requests. Exchanged from a secret key, valid 300 seconds. |
| Refresh token | `r1rt_…` | Server only. Exchanges for a new access token; valid 3,900 seconds, single-use (each refresh rotates it). |
| Redirect secret | `rsec_…` | Server only. Signs and verifies hosted-checkout redirect callbacks. |
| Webhook secret | `whsec_…` | Server only. Verifies webhook signatures. |

The environment a key belongs to is determined entirely by its prefix — a `_test_` key never works against production, and vice versa.

## Getting keys

The exact self-service flow for provisioning keys, webhook endpoints, redirect secrets, and allowed redirect domains is still being finalized. Until then, [contact support](/resources/support) to request sandbox and production keys for your account, including how many keys you can hold at once.

## Least-privilege keys

Secret keys can carry any of RadiumOne's API scopes (payment creation, capture, void, referenced and standalone refunds, session management, and more). By default a new secret key is issued with **every** scope enabled — but having the refund scope isn't the same as being able to refund: the acquirer channel itself must also have the `REFUND` operation enabled, which isn't on by default. See [Refunds require enablement](/payments-api/refund#refunds-require-enablement).

<Tip>
  When you request a secret key, ask for only the scopes your integration actually needs. In particular, leave out the standalone-refund scope unless you use that operation — it's high-risk and covered separately in [Standalone refunds](/payments-api/standalone-refunds).
</Tip>

Publishable keys are always scoped to session creation only — they can never create, capture, void, or refund a payment directly, which is why it's safe to expose them in browser code.

## Outlet-scoped keys

A key can be bound to a specific outlet (store/location). If you omit `outlet_id` on a request, RadiumOne uses the key's bound outlet by default. Sending an `outlet_id` that doesn't match the key's binding fails with a 403 error; every response echoes back the outlet the request was actually resolved against.

## Key safety

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

Rotating or revoking a secret or publishable key, and emergency revocation if a key leaks, both go through [Support](/resources/support#request-enablement) today. Access tokens and refresh tokens are yours to manage directly — see the next section.

## Exchange a secret key for an access token

Payments API requests are authenticated with a short-lived access token, not the secret key itself — exchange your secret key once, cache the token for up to its `expires_in` (300 seconds), and refresh it before it lapses.

<Card title="Authentication" icon="key" href="/get-started/api-basics/authentication">
  The full token exchange, refresh, and revoke flow, including sample requests.
</Card>

## Moving to production

1. Request production keys (see [Getting keys](#getting-keys) above).
2. Swap every `_test_` key for its `_prod_` equivalent.
3. Point your integration at the production hosts instead of the sandbox hosts.
4. Update your webhook endpoint and redirect secret for the production environment.
5. Work through the [go-live checklist](/resources/go-live-checklist) before you accept real payments.

## Next steps

<Columns cols={2}>
  <Card title="Quickstart" icon="rocket" href="/get-started/quickstart">
    Accept your first sandbox payment with the keys you just requested.
  </Card>

  <Card title="Authentication" icon="key" href="/get-started/api-basics/authentication">
    Full reference for the token, refresh, and revoke endpoints.
  </Card>

  <Card title="Security and PCI scope" icon="shield-check" href="/resources/security-and-pci">
    Key storage, rotation, and monitoring guidance.
  </Card>

  <Card title="Support" icon="life-buoy" href="/resources/support">
    Request keys, enablement, or emergency key revocation.
  </Card>
</Columns>
