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

# Cancel a session - Hosted checkout

> Cancel a pending checkout session before the shopper pays — for example, when the order changes or the shopper leaves.



## OpenAPI

````yaml /openapi/radiumone-checkout-api.yaml post /api/v1/checkout/sessions/{id}/cancel
openapi: 3.1.0
info:
  title: RadiumOne Checkout API
  version: 0.5.2
  description: >-
    The Checkout API creates and manages hosted-checkout sessions. It is
    hand-authored against the HPP team's current merchant contract — the
    shopper's browser is redirected to (or embeds) a RadiumOne-hosted payment
    page, and your server creates, retrieves, and cancels the session behind it.
    See [Hosted checkout](/hosted-checkout/overview).

    Responses use a simple envelope: `{status, data}` (no `request_id`, unlike
    the Payments API). Errors mirror the Payments API's RFC 9457 shape, plus a
    deprecated top-level `error` field kept for backward compatibility — read
    `type`/`detail`, not `error`.
servers:
  - url: https://checkout-sandbox.radiumone.io
    description: Sandbox
  - url: https://checkout.radiumone.io
    description: Production
security:
  - apiKeyAuth: []
tags:
  - name: Checkout sessions
    description: Create, retrieve, and cancel hosted-checkout sessions.
paths:
  /api/v1/checkout/sessions/{id}/cancel:
    post:
      tags:
        - Checkout sessions
      summary: Cancel a checkout session
      description: Cancel a pending checkout session before the shopper pays.
      operationId: cancelCheckoutSession
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Session cancelled.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  data:
                    type: object
                    properties:
                      checkout_id:
                        type: string
                      status:
                        type: string
              example:
                status: ok
                data:
                  checkout_id: chk_3f9a1c2e5b7d4a608e1f2c3b4d5e6f70
                  status: cancelled
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: >-
            The session is no longer cancellable — it's `processing`, or already
            `completed`, `failed`, or `expired`. Cancelling an
            already-`cancelled` session is idempotent and returns `200`, not
            this error.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
              example:
                type: urn:radiumone:checkout:session-invalid-state
                title: RadiumOne error
                status: 409
                detail: Cannot cancel a processing session
                code: session:invalid_state
                error:
                  code: session:invalid_state
                  message: Cannot cancel a processing session
        '429':
          $ref: '#/components/responses/TooManyRequests'
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >
            #!/usr/bin/env bash

            # Merchant-initiated cancel (X-Api-Key, not CSRF/customer-driven).
            Idempotent

            # while pending; 409 if already processing or terminal.

            set -euo pipefail


            CHECKOUT_BASE="${RADIUMONE_CHECKOUT_BASE:-https://checkout-sandbox.radiumone.io}"

            : "${RADIUMONE_SECRET_KEY:?set RADIUMONE_SECRET_KEY to your r1sk_*
            secret key}"

            : "${RADIUMONE_CHECKOUT_ID:?set RADIUMONE_CHECKOUT_ID to the session
            to cancel}"


            curl -sS -X POST
            "$CHECKOUT_BASE/api/v1/checkout/sessions/$RADIUMONE_CHECKOUT_ID/cancel"
            \
              -H "X-Api-Key: $RADIUMONE_SECRET_KEY"
        - lang: javascript
          label: Node.js
          source: >
            #!/usr/bin/env node

            // Merchant-initiated cancel (X-Api-Key, not CSRF/customer-driven).
            Idempotent

            // while pending; 409 if already processing or terminal. Node 18+
            ESM fetch.

            // Env: RADIUMONE_SECRET_KEY, RADIUMONE_CHECKOUT_ID,
            RADIUMONE_CHECKOUT_BASE.

            const CHECKOUT_BASE = process.env.RADIUMONE_CHECKOUT_BASE ||
            "https://checkout-sandbox.radiumone.io";

            const secretKey = process.env.RADIUMONE_SECRET_KEY;

            const checkoutId = process.env.RADIUMONE_CHECKOUT_ID;


            async function cancelCheckoutSession() {
              const res = await fetch(`${CHECKOUT_BASE}/api/v1/checkout/sessions/${checkoutId}/cancel`, {
                method: "POST",
                headers: { "X-Api-Key": secretKey },
              });
              const payload = await res.json();
              if (!res.ok) {
                // 409 session:invalid_state if already processing/terminal.
                throw new Error(`checkout session cancel failed: ${payload.code ?? payload.type} (${res.status})`);
              }
              return payload;
            }


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

            """Merchant-initiated cancel (X-Api-Key, not CSRF/customer-driven).
            Idempotent

            while pending; 409 if already processing or terminal.

            """

            import json

            import os


            import requests


            CHECKOUT_BASE = os.environ.get("RADIUMONE_CHECKOUT_BASE",
            "https://checkout-sandbox.radiumone.io")



            def cancel_checkout_session() -> dict:
                checkout_id = os.environ["RADIUMONE_CHECKOUT_ID"]
                resp = requests.post(
                    f"{CHECKOUT_BASE}/api/v1/checkout/sessions/{checkout_id}/cancel",
                    headers={"X-Api-Key": os.environ.get("RADIUMONE_SECRET_KEY", "")},
                    timeout=30,
                )
                payload = resp.json()
                if not resp.ok:
                    # 409 session:invalid_state if already processing/terminal.
                    code = payload.get("code") or payload.get("type")
                    raise RuntimeError(f"checkout session cancel failed: {code} ({resp.status_code})")
                return payload


            if __name__ == "__main__":
                print(json.dumps(cancel_checkout_session(), indent=2))
components:
  responses:
    Unauthorized:
      description: '`X-Api-Key` is missing, malformed, or not recognized by the gateway.'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: urn:radiumone:checkout:missing-credentials
            title: RadiumOne error
            status: 401
            detail: X-Api-Key header is required.
            code: urn:radiumone:checkout:missing-credentials
            error:
              code: urn:radiumone:checkout:missing-credentials
              message: X-Api-Key header is required.
    NotFound:
      description: >-
        `resource:not_found`: the `id` or the API key is malformed.
        `session:not_found`: no session with this id exists for your merchant —
        either it never existed, it belongs to another merchant (the two are
        deliberately indistinguishable, same body either way), or it is past
        retention.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            sessionNotFound:
              summary: No such session
              value:
                type: urn:radiumone:checkout:session-not-found
                title: Checkout session not found
                status: 404
                detail: Checkout session not found
                code: session:not_found
                error:
                  code: session:not_found
                  message: Checkout session not found
            malformed:
              summary: Malformed id or key
              value:
                type: urn:radiumone:checkout:resource-not-found
                title: Not found
                status: 404
                detail: Not found
                code: resource:not_found
                error:
                  code: resource:not_found
                  message: Not found
    TooManyRequests:
      description: Rate limit exceeded. Retry after the given number of seconds.
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds to wait before retrying.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
  schemas:
    Problem:
      type: object
      description: >-
        RFC 9457 problem details, `application/problem+json`. `type` is
        auto-derived from `code` as `urn:radiumone:checkout:<code, `:`/`_`
        replaced with `-`>` — branch on `type` (or the equivalent `code`), never
        on `title`, which is a short label and not guaranteed stable across
        error paths for the same `code`.
      properties:
        type:
          type: string
          format: uri
          description: Stable tag URI. Branch on this.
        title:
          type: string
          description: >-
            Short label. Don't branch on it — many error paths share the generic
            title "RadiumOne error".
        status:
          type: integer
        detail:
          type: string
          description: >-
            Human-readable detail; may echo submitted input. Can change — don't
            parse it.
        instance:
          type: string
          description: Request path that produced the error, no query string.
        code:
          type: string
          description: >-
            Stable dotted code, same meaning as `type`, kept for backward
            compatibility.
        details:
          type: object
          description: >-
            Typed extras for some errors, for example `retry_after` (seconds) on
            a 429.
        error:
          type: object
          deprecated: true
          description: >-
            Legacy mirror of `code`/`detail`, kept for backward compatibility.
            Prefer `type`/`detail`.
          properties:
            code:
              type: string
            message:
              type: string
      required:
        - type
        - title
        - status
        - detail
        - code
        - error
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: >-
        Your secret key (`r1sk_...`). A publishable key is rejected with `400
        urn:radiumone:checkout:wrong-key-type`.

````