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

# Install and load - Elements SDK

> Add RadiumOne Elements to your page with npm (recommended), a CDN script tag, or React — and understand each option's Subresource Integrity guarantees.

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

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

Load Elements with npm if you can — the loader bakes in a Subresource Integrity (SRI) hash for you, so there's nothing to copy or keep in sync. Use the CDN script tag only if your build can't take an npm dependency.

<Tabs>
  <Tab title="npm">
    Install the core package:

    ```bash theme={null}
    npm install @cubepay/radiumone-js
    ```

    Then load the SDK with `loadRadiumOne()`. It injects the matching CDN `<script>` for you, with a Subresource Integrity hash that's baked into the npm package at publish time — you never need to look up or paste a hash yourself.

    ```js theme={null}
    import { loadRadiumOne } from "@cubepay/radiumone-js";

    // Call once, at module scope. Test/mock keys automatically load the sandbox bundle.
    const radiumone = await loadRadiumOne("r1pk_test_YOUR_KEY");
    ```

    * `loadRadiumOne()` returns a shared instance for the page. Calling it again with a **different** key logs a warning and returns the existing instance — don't call it more than once per key.
    * **SSR-safe:** it resolves to `null` when there's no `window` (for example, during a Next.js server render). Guard for `null` before using the result.
    * The load has a 10-second timeout; a failure rejects the promise. See [Handle Elements failing to load](/elements/handle-failures/sdk-fails-to-load) for how to detect and recover from a load failure.
  </Tab>

  <Tab title="CDN">
    Load the script directly with a pinned version and its Subresource Integrity hash:

    ```html HTML theme={null}
    <!--
      Load RadiumOne Elements from the CDN with Subresource Integrity (SRI).
      Get the integrity hash below from the release notes for this pinned
      version — never take it only from the SRI manifest served at the same
      path, since that manifest can't vouch for its own origin. (Public release
      notes with SRI hashes are not yet published for every version.)
      Pin the immutable /elements/v<VERSION>/ path; never use /elements/v1/ or
      /elements/latest/ in production.
    -->
    <script
      src="https://js-sandbox.radiumone.io/elements/v1.6.0/radiumone.min.js"
      integrity="sha384-CONFIRM_SDK1_SRI_HASH"
      crossorigin="anonymous"
    ></script>
    <script>
      const { RadiumOne } = window.RadiumOneSDK;
      const radiumone = RadiumOne.init("r1pk_test_YOUR_KEY"); // sync, browser-safe key only
    </script>
    ```

    * Pin the **immutable** `/elements/v<X.Y.Z>/` path and its `integrity` hash — see [Subresource Integrity](#subresource-integrity) for where to get the hash.
    * Your Content Security Policy must allow the CDN in `script-src` and `frame-src` — see [Content Security Policy](/elements/content-security-policy).
    * After the script loads, the SDK is available as `window.RadiumOneSDK`:

      ```js theme={null}
      const { RadiumOne } = window.RadiumOneSDK;
      const radiumone = RadiumOne.init("r1pk_test_YOUR_KEY"); // synchronous
      ```
  </Tab>

  <Tab title="React">
    Install both packages:

    ```bash theme={null}
    npm install @cubepay/radiumone-js @cubepay/react-radiumone-js
    ```

    Call `loadRadiumOne()` once at module scope and pass the resulting promise to `<RadiumOneProvider>`:

    ```tsx theme={null}
    import { loadRadiumOne } from "@cubepay/radiumone-js";
    import { RadiumOneProvider } from "@cubepay/react-radiumone-js";

    const radiumone = loadRadiumOne("r1pk_test_YOUR_KEY");

    export function App() {
      return (
        <RadiumOneProvider radiumone={radiumone}>
          <Checkout />
        </RadiumOneProvider>
      );
    }
    ```

    See the full walkthrough, including components and hooks, on the [React reference page](/elements/reference/react).
  </Tab>
</Tabs>

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

## Subresource Integrity

Subresource Integrity (SRI) makes the browser refuse to run the SDK script if its contents don't match a known hash — so a tampered script never loads.

| How you load | What you do |
| - | - |
| npm (`loadRadiumOne()`) or React | Nothing — the loader adds the `integrity` hash for the version it loads, built into the package |
| CDN `<script>` tag | Add `integrity="sha384-…"` and `crossorigin="anonymous"` to the tag, with the hash for the exact version you pin |

### Get the hash for a CDN script tag

* **Release notes** — each version's release notes include the `<script>` tag with its `integrity` hash. Use these as your source of truth.&#x20;
* **SRI manifest** — for scripted version bumps, each version publishes its hashes at <code>{productionCdnHost}/elements/v{"<X.Y.Z>"}/sri.json</code> (sandbox: <code>{sandboxCdnHost}/elements/v{"<X.Y.Z>"}/sri.json</code>). The manifest is served from the same host as the script, so it can't vouch for that host — check the hash against the release notes before you ship it.

```json sri.json theme={null}
{
  "version": "<X.Y.Z>",
  "publishedAt": "2026-05-08T12:34:56Z",
  "algorithm": "sha384",
  "files": {
    "radiumone.min.js": "sha384-…",
    "field.js": "sha384-…"
  }
}
```

Use `files["radiumone.min.js"]` for your script tag. You don't pin `field.js` — the card iframe checks its own hash.

### Pin only a versioned path

| Path | Changes? | Use `integrity`? |
| - | - | - |
| `/elements/v<X.Y.Z>/radiumone.min.js` | Never | **Yes** |
| `/elements/v1/radiumone.min.js` | On every release | No — the hash stops matching and the script is blocked |
| `/elements/latest/radiumone.min.js` | On every release | No — for discovery only, not production |

When you move to a new version, update the path and the hash together.

## Runtime attestation

Beyond SRI, the card-field iframe reports its own script hash and version on every tokenize call, and RadiumOne compares it against the expected release. If a script was tampered with in transit, tokenization fails with `auth:invalid-script-hash` rather than silently succeeding — see [Tokenization errors](/elements/errors/tokenization-errors). You don't need to configure anything for this; it runs automatically.

## Server-side rendering

`loadRadiumOne()` returns `null` during SSR (no `window`). Only call SDK methods once you have a non-null instance — the React provider and hooks already handle this for you (`useRadiumOne()` returns `null` until the SDK finishes loading in the browser).

## Key validation errors

`RadiumOne.init()` / `loadRadiumOne()` throw an [`ElementsError`](/elements/errors/sdk-and-integration-errors) if the publishable key is missing or malformed:

| Code | Meaning |
| - | - |
| `api:invalid_key` | No key was passed |
| `api:secret_key_used` | A secret key (`r1sk_…`) was passed instead of a publishable key |
| `api:invalid_key_format` | The key doesn't match a known prefix |
| `api:test_key_in_prod_build` | A test key was used with the production CDN bundle |
| `api:prod_key_in_staging_build` | A production key was used with a staging/beta bundle |
| `loader:integrity_unset` | npm only — the installed package's build channel doesn't match the key's channel (for example, a production package build with a test key) |

See [Fix publishable key errors](/elements/handle-failures/invalid-publishable-key) for how to detect and fix each of these.

## Next steps

<Columns cols={2}>
  <Card title="Accept a card payment" icon="credit-card" href="/elements/accept-a-card-payment">
    Mount a card field, tokenize, and charge your first test payment.
  </Card>

  <Card title="Content Security Policy" icon="shield-check" href="/elements/content-security-policy">
    CSP directives Elements needs on your checkout page.
  </Card>
</Columns>
