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

# Create tokenization session - Payments API

> Create a tokenization session so the Elements SDK can collect card details in the browser and return a card token to your server.



## OpenAPI

````yaml /openapi/radiumone-payments-api.yaml post /v1/sessions
openapi: 3.1.0
info:
  description: |
    The Payments API lets your server create tokenization sessions, charge and
    manage payments, check loyalty balances, and manage your hosted-checkout
    branding and redirect secret. Generated for merchant integrators —
    internal, admin, and service-to-service surfaces are excluded.

    All responses share an envelope: `{status, data, request_id}`. The
    envelope's `request_id` is an HTTP correlation ID — it echoes your
    `X-Request-Id` request header (letters, digits, hyphens, max 36 characters)
    or one is generated for you. It is **not** the idempotency key you send in
    a transaction request body (also confusingly named `request_id` there) —
    the two are unrelated; see
    [Request conventions](/get-started/api-basics/request-conventions). Errors
    use [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)
    `application/problem+json` bodies — see
    [Authentication](/get-started/api-basics/authentication) and
    [Request conventions](/get-started/api-basics/request-conventions) for the
    shared error shape, and [Problem format and
    retries](/payments-api/errors/problem-format-and-retries) for the response
    shape, status guide, and retry rules.
  summary: Transaction orchestration and processor aggregation for RadiumOne.
  title: RadiumOne Payment Gateway
  version: 1.3.0
servers:
  - url: https://api-sandbox.radiumone.io/gateway
    description: Sandbox
  - url: https://api.radiumone.io/gateway
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: Exchange, refresh, and revoke access tokens.
  - name: Merchant settings
    description: >-
      Manage your hosted-checkout redirect secret, checkout configuration, and
      account config.
  - name: Payment methods
    description: Discover which payment methods and brands are available.
  - name: Sessions
    description: Tokenization sessions used to collect card data with RadiumOne Elements.
  - name: Settlement
    description: Settlement batch status lookup.
  - name: Payments
    description: Create and manage card transactions.
  - name: Rewards
    description: UOB Rewards loyalty balance inquiry.
  - name: Refunds
    description: Return funds to a shopper.
  - name: Transactions
    description: Check the live status of a transaction.
paths:
  /v1/sessions:
    post:
      tags:
        - Sessions
      summary: Create tokenization session
      description: >-
        Create a card tokenization session for a checkout.


        Returns the `session_id`, the `session_secret` and the public key
        material your

        payment page or SDK needs to collect and encrypt card details, plus the
        session's

        expiry. Card data never passes through your servers.


        Optional behaviour:

        - `success_url` / `cancel_url` must use a host in your allowed domains
        (422 otherwise).

        - Supplying `currency` also returns the payment methods available for an
        e-commerce
          checkout in that currency, your enabled currencies, the resolved `outlet_id` and a
          3DS requirement hint. A currency that is not enabled for you returns 422; an
          explicitly requested outlet that does not exist returns 404, and one that differs
          from the outlet your API key is bound to returns 403. If no payment methods are
          available, `payment_methods` is an empty list rather than an error.

        Returns 409 if your account cannot yet be used for tokenization, and 503
        if the session

        could not be created; retry later.
      operationId: create_session_v1_sessions_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSessionRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessResponse_SessionCreatedResponse_'
              example:
                status: ok
                request_id: req_c3d4e5f6a1b2
                data:
                  session_id: sess_5f8a1c2e10
                  session_secret: <opaque, pass byte-for-byte to Elements>
                  pubkey_jws: <opaque JWS, pass byte-for-byte to Elements>
                  expires_at: '2026-09-14T10:30:00.000Z'
                  status: open
                  currency: SGD
                  outlet_id: null
                  payment_methods:
                    - type: card
                      display_name: Card
                      priority_rank: 10
                  allowed_currencies:
                    - SGD
                  three_ds_requirement:
                    status: possible
                    mandatory: false
                    channel: ECOMMERCE
          description: Successful Response
        '400':
          description: The request body failed validation.
          x-docs-interim: true
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '401':
          content:
            application/problem+json:
              example:
                detail: Missing or invalid Bearer token.
                status: 401
                title: Authentication Required
                type: urn:radiumone:gateway:authentication-required
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: Missing or invalid Bearer token.
        '403':
          content:
            application/problem+json:
              example:
                detail: Insufficient permissions for this operation.
                status: 403
                title: Permission Denied
                type: urn:radiumone:gateway:permission-denied
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: Insufficient permissions for this operation.
        '404':
          content:
            application/problem+json:
              example:
                detail: The requested resource does not exist.
                status: 404
                title: Not Found
                type: urn:radiumone:gateway:not-found
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: The requested resource does not exist.
        '409':
          content:
            application/problem+json:
              example:
                detail: >-
                  Your merchant account is not yet set up for card tokenization
                  and could not be set up automatically. Retry later; contact
                  support if the problem continues.
                status: 409
                title: Merchant Not Provisioned
                type: urn:radiumone:gateway:merchant-not-provisioned
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: >-
            Your merchant account is not yet set up for card tokenization and
            could not be set up automatically. Retry later; contact support if
            the problem continues.
        '422':
          description: >-
            `currency` is not enabled for your account, or a redirect URL's host
            isn't in your allowed domains.
          x-docs-interim: true
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          content:
            application/problem+json:
              example:
                detail: >-
                  Too many bind attempts for this session; the session is
                  temporarily locked. This is a lockout, not a transient error
                  -- do not auto-retry.
                status: 429
                title: Bind Rate Limit
                type: urn:radiumone:gateway:bind-rate-limit
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: >-
            Too many bind attempts for this session; the session is temporarily
            locked. This is a lockout, not a transient error -- do not
            auto-retry.
        '500':
          content:
            application/problem+json:
              example:
                detail: An unexpected error occurred.
                status: 500
                title: Internal Server Error
                type: urn:radiumone:gateway:internal-server-error
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: An unexpected error occurred.
        '503':
          content:
            application/problem+json:
              example:
                detail: >-
                  A downstream dependency is unavailable or did not respond in
                  time.
                status: 503
                title: Service Unavailable
                type: urn:radiumone:gateway:service-unavailable
              schema:
                properties:
                  detail:
                    type: string
                  status:
                    type: integer
                  title:
                    type: string
                  type:
                    type: string
                type: object
          description: A downstream dependency is unavailable or did not respond in time.
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >
            #!/usr/bin/env bash

            # Create a tokenization session for Elements. Pass
            session_id/session_secret/

            # pubkey_jws to the browser unchanged — never re-serialize
            pubkey_jws.

            set -euo pipefail


            API_BASE="${RADIUMONE_API_BASE:-https://api-sandbox.radiumone.io/gateway}"

            : "${RADIUMONE_ACCESS_TOKEN:?set RADIUMONE_ACCESS_TOKEN to a Bearer
            access token}"


            curl -sS -X POST "$API_BASE/v1/sessions" \
              -H "Content-Type: application/json" \
              -H "Authorization: Bearer $RADIUMONE_ACCESS_TOKEN" \
              -d @request.json
        - lang: javascript
          label: Node.js
          source: >
            #!/usr/bin/env node

            // Create a tokenization/checkout session for Elements. Node 18+ ESM
            fetch.

            // Env: RADIUMONE_ACCESS_TOKEN, RADIUMONE_API_BASE (optional
            override).

            import { readFileSync } from "node:fs";


            const API_BASE = process.env.RADIUMONE_API_BASE ||
            "https://api-sandbox.radiumone.io/gateway";

            const accessToken = process.env.RADIUMONE_ACCESS_TOKEN;

            const body = JSON.parse(readFileSync(new URL("./request.json",
            import.meta.url)));


            async function createPaymentSession() {
              const res = await fetch(`${API_BASE}/v1/sessions`, {
                method: "POST",
                headers: {
                  "Content-Type": "application/json",
                  Authorization: `Bearer ${accessToken}`,
                },
                body: JSON.stringify(body),
              });
              const payload = await res.json();
              if (!res.ok) {
                throw new Error(`sessions create failed: ${payload.type ?? payload.code} (${res.status})`);
              }
              // Pass session_id, session_secret and pubkey_jws to the browser byte-for-byte.
              return payload;
            }


            createPaymentSession().then((r) => console.log(JSON.stringify(r,
            null, 2)));
        - lang: python
          label: Python
          source: >
            #!/usr/bin/env python3

            """Create a tokenization/checkout session for Elements. Python
            3.10+, requests."""

            import json

            import os

            from pathlib import Path


            import requests


            API_BASE = os.environ.get("RADIUMONE_API_BASE",
            "https://api-sandbox.radiumone.io/gateway")



            def create_payment_session() -> dict:
                body = json.loads((Path(__file__).parent / "request.json").read_text())
                resp = requests.post(
                    f"{API_BASE}/v1/sessions",
                    json=body,
                    headers={"Authorization": f"Bearer {os.environ.get('RADIUMONE_ACCESS_TOKEN', '')}"},
                    timeout=30,
                )
                payload = resp.json()
                if not resp.ok:
                    raise RuntimeError(f"sessions create failed: {payload.get('type') or payload.get('code')} ({resp.status_code})")
                # Pass session_id, session_secret and pubkey_jws to the browser byte-for-byte.
                return payload


            if __name__ == "__main__":
                print(json.dumps(create_payment_session(), indent=2))
components:
  schemas:
    CreateSessionRequest:
      description: >-
        Optional body for creating a checkout session.


        Every field is optional. You don't send your merchant ID -- it is taken
        from your

        access token.
      properties:
        amount:
          anyOf:
            - minimum: 0
              type: integer
            - type: 'null'
          description: >-
            Amount in smallest currency unit (optional; enables
            amount-conditioned discovery).
          title: Amount
        cancel_url:
          anyOf:
            - maxLength: 2048
              type: string
            - type: 'null'
          description: >-
            Payment-cancel redirect URL. Validated against the merchant's
            allowed_domains (422 on mismatch).
          title: Cancel Url
        currency:
          anyOf:
            - maxLength: 3
              minLength: 3
              pattern: ^[A-Za-z]{3}$
              type: string
            - type: 'null'
          description: >-
            ISO 4217 currency code. When set, response includes supported
            payment_methods.
          title: Currency
        ip_address:
          anyOf:
            - maxLength: 45
              type: string
            - type: 'null'
          description: Your customer's IP address, used as a fraud signal (optional).
          title: Ip Address
        outlet_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Outlet UUID for discovery. Defaults to the merchant's DEFAULT
            outlet.
          title: Outlet Id
        success_url:
          anyOf:
            - maxLength: 2048
              type: string
            - type: 'null'
          description: >-
            Post-payment redirect URL. Validated against the merchant's
            allowed_domains (422 on mismatch).
          title: Success Url
        ttl_minutes:
          anyOf:
            - maximum: 60
              minimum: 5
              type: integer
            - type: 'null'
          description: How long the session stays valid, in minutes (5–60). Defaults to 30.
          title: Ttl Minutes
        user_agent:
          anyOf:
            - maxLength: 512
              type: string
            - type: 'null'
          description: >-
            Your customer's browser User-Agent, used as a fraud signal
            (optional).
          title: User Agent
      title: CreateSessionRequest
      type: object
    SuccessResponse_SessionCreatedResponse_:
      description: >-
        Standard success envelope. Every successful response has this shape,
        with the operation's own payload under `data`.
      properties:
        data:
          anyOf:
            - $ref: '#/components/schemas/SessionCreatedResponse'
            - type: 'null'
          description: >-
            The operation's result. Its shape is documented per operation;
            omitted on responses that carry no payload.
        message:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Optional human-readable note. Omitted from the response when not
            set, which is the case for every payment operation today. Never
            parse it.
          title: Message
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Correlation ID for this HTTP request, for logs and support. Send
            your own in the `X-Request-Id` header (letters, digits and hyphens,
            up to 36 characters -- other characters are stripped) or the gateway
            generates one. This is NOT the `request_id` idempotency key you send
            in a transaction body; the two are unrelated.
          title: Request Id
        status:
          default: ok
          description: >-
            Always `ok` on a successful (2xx) response. Errors use a different
            body shape entirely (RFC 9457 problem details), so branch on the
            HTTP status code, not on this field.
          title: Status
          type: string
      title: SuccessResponse[SessionCreatedResponse]
      type: object
    Problem:
      type: object
      x-docs-interim: true
      description: >-
        RFC 9457 problem details. Returned with `Content-Type:
        application/problem+json`. Interim: not yet a named component in the
        gateway team's published contract — every response there inlines its own
        smaller ad-hoc object; this shape reflects what our error pages and
        error-catalog.json actually document.
      properties:
        type:
          type: string
          format: uri
          description: >-
            A URN identifying the error condition, e.g.
            `urn:radiumone:gateway:validation-error`.
        title:
          type: string
          description: Short
          human-readable summary of the error type.: null
        status:
          type: integer
          description: The HTTP status code
          repeated in the body for convenience.: null
        detail:
          type: string
          description: Human-readable explanation specific to this occurrence.
        instance:
          type: string
          description: The request path that produced this error.
        request_id:
          type: string
          description: >-
            Correlation ID for this request (see the envelope `request_id` note
            above). Include it when contacting support.
        code:
          type: string
          description: Optional short machine-readable code
          distinct from `type`.: null
        retry_allowed:
          type: boolean
          description: >-
            When present, whether it's safe to retry with the same idempotency
            key.
        errors:
          type: array
          description: >-
            Present on most `urn:radiumone:gateway:validation-error` (400)
            responses — one entry per invalid field. Some 400s of this type are
            raised by checks that run after validation and have no `errors`
            array; always handle it being absent. Rely on `pointer`/`parameter`
            and `code`, not the wording of `detail`, which can change.
          items:
            type: object
            properties:
              pointer:
                type: string
                description: >-
                  JSON Pointer to the invalid field in the request body, e.g.
                  `/amount/currency` or `/items/0/name`. An empty string means
                  the whole request (e.g. the body isn't valid JSON).
              parameter:
                type: string
                description: >-
                  Name of the invalid query or path parameter. Set instead of
                  `pointer` when the failing value came from the URL, not the
                  body.
              code:
                type: string
                description: >-
                  Machine-readable error type for this field, e.g. `missing` or
                  `string_too_long`.
              detail:
                type: string
                description: Human-readable explanation for this field.
      required:
        - type
        - title
        - status
        - detail
    SessionCreatedResponse:
      description: Response body for POST /v1/sessions (pass-through from tokenization).
      properties:
        allowed_currencies:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          description: >-
            Merchant's full allowed-currency list (for multi-currency checkout
            selectors).
          title: Allowed Currencies
        currency:
          anyOf:
            - type: string
            - type: 'null'
          description: ISO 4217 currency the payment methods were resolved for.
          title: Currency
        expires_at:
          anyOf:
            - type: string
            - type: 'null'
          description: ISO 8601 session expiry timestamp.
          title: Expires At
        outlet_id:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Resolved outlet UUID the payment methods were resolved for -- the
            key-bound outlet if the API key is outlet-bound, otherwise the
            merchant's DEFAULT outlet. Null when discovery did not run (no
            `currency`) or could not resolve an outlet.
          title: Outlet Id
        payment_methods:
          anyOf:
            - items:
                $ref: '#/components/schemas/PaymentMethodSummary'
              type: array
            - type: 'null'
          description: >-
            Supported payment method types for (merchant, outlet, currency,
            ECOMMERCE).
          title: Payment Methods
        pubkey:
          anyOf:
            - $ref: '#/components/schemas/JwePublicKey'
            - type: 'null'
          description: >-
            DEPRECATED. The card-encryption key for this session in plain form,
            kept only for older checkout integrations. Use `pubkey_jws` instead
            -- this field will be removed.
        pubkey_jws:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Compact-JWS (ES256) of the per-session card-encryption JWK.
            Canonical: the SDK verifies the signature against its bundle-pinned
            tokenization signing key and reads the JWK from the payload. Relayed
            byte-for-byte from tokenization; the gateway does not sign or
            re-encode it.
          title: Pubkey Jws
        session_id:
          description: Opaque session identifier.
          title: Session Id
          type: string
        session_secret:
          description: Per-session HMAC secret for SDK bind call.
          title: Session Secret
          type: string
        status:
          anyOf:
            - type: string
            - type: 'null'
          description: Session status (e.g. pending).
          title: Status
        three_ds_requirement:
          anyOf:
            - $ref: '#/components/schemas/ThreeDsRequirementAdvisory'
            - type: 'null'
          description: >-
            Whether 3-D Secure is likely to be required, so your checkout page
            can show what to expect before a card is entered. Null when no
            `currency` was supplied on the request. It is a hint, not a
            guarantee.
      required:
        - session_id
        - session_secret
      title: SessionCreatedResponse
      type: object
    PaymentMethodSummary:
      description: PM-type-level projection for GET /checkout/supported-payment-methods.
      properties:
        display_name:
          description: Human-readable label.
          title: Display Name
          type: string
        priority_rank:
          description: >-
            Suggested display order for this payment method on your checkout,
            lowest first.
          title: Priority Rank
          type: integer
        type:
          description: Payment method type slug.
          title: Type
          type: string
      required:
        - type
        - display_name
        - priority_rank
      title: PaymentMethodSummary
      type: object
    JwePublicKey:
      description: The public key for this checkout session, used to encrypt card details.
      properties:
        alg:
          description: Algorithm (e.g. RSA-OAEP-256).
          title: Alg
          type: string
        e:
          anyOf:
            - type: string
            - type: 'null'
          description: RSA exponent (base64url).
          title: E
        kid:
          description: Key identifier (bare numeric KMS key version).
          title: Kid
          type: string
        kty:
          description: Key type (e.g. RSA).
          title: Kty
          type: string
        'n':
          anyOf:
            - type: string
            - type: 'null'
          description: RSA modulus (base64url).
          title: 'N'
        use:
          anyOf:
            - type: string
            - type: 'null'
          description: Key use (e.g. enc).
          title: Use
      required:
        - kid
        - kty
        - alg
      title: JwePublicKey
      type: object
    ThreeDsRequirementAdvisory:
      description: >-
        Whether 3-D Secure is likely to be required for this checkout.


        A hint you can use to prepare your checkout before a card is entered. It
        is not a

        guarantee: the final decision is made once the card is known.
      properties:
        channel:
          description: Channel the advisory was computed for (e.g. ECOMMERCE).
          title: Channel
          type: string
        mandatory:
          description: >-
            True when at least one candidate acquirer mandates 3DS for the
            channel.
          title: Mandatory
          type: boolean
        status:
          description: >-
            Aggregate intent across candidate acquirers: 'expected' (a candidate
            mandates 3DS), 'possible' (a candidate has 3DS enabled), 'off'
            (none), or 'not_applicable' (channel cannot run 3DS).
          title: Status
          type: string
      required:
        - status
        - mandatory
        - channel
      title: ThreeDsRequirementAdvisory
      type: object
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer access token from `POST /v1/auth/token`. Treat it as an opaque
        string — do not depend on its internal encoding, which has changed
        before and isn't part of the contract.
      x-docs-interim: true

````