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

# Check transaction status - Payments API

> Query a transaction's live status directly from the acquirer, to recover after a timeout or resolve a PENDING result.

RadiumOne doesn't expose a general list or get-by-ID endpoint for transactions. The one merchant-facing read is a **live status inquiry**: given a transaction `id` you already have, RadiumOne asks the original acquirer for its current status and returns it — without writing anything.

<Info>
  This request requires a valid access token. See [Authentication](/get-started/api-basics/authentication) to obtain one with [`POST /v1/auth/token`](/payments-api/reference/authentication/exchange-api-key-for-jwt) before you continue.
</Info>

## When to use it

* You have a transaction `id` (from a create response, a replay, or a webhook) and want its current status before you decide what to do next.
* A create-type call timed out and you've already replayed it with the same `request_id`/`operation_id` to recover the `id` — see [Handle timeouts and unknown outcomes](/payments-api/handle-failures/timeouts-and-unknown-outcomes).
* A transaction is `PENDING` and you want to check whether it's resolved instead of waiting for the webhook.

If you don't have a transaction `id` yet, status inquiry can't help — replay the original request with the same idempotency key first, or wait for the confirming webhook.

## Steps

<Steps>
  <Step title="Query the transaction's status">
    [API reference](/payments-api/reference/transactions/transaction-status-inquiry).

    <CodeGroup>
      ```bash cURL theme={null}
      #!/usr/bin/env bash
      # Live acquirer status inquiry for a transaction (no new row written). Use
      # this to recover after a timeout instead of guessing the outcome.
      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}"
      : "${RADIUMONE_TRANSACTION_ID:?set RADIUMONE_TRANSACTION_ID to the transaction to inquire}"

      curl -sS "$API_BASE/v1/transactions/$RADIUMONE_TRANSACTION_ID/status" \
        -H "Authorization: Bearer $RADIUMONE_ACCESS_TOKEN"
      ```

      ```javascript Node.js theme={null}
      #!/usr/bin/env node
      // Live acquirer status inquiry for a transaction (no new row written). Use
      // this to recover after a timeout instead of guessing the outcome. Node 18+
      // ESM fetch. Env: RADIUMONE_ACCESS_TOKEN, RADIUMONE_TRANSACTION_ID, RADIUMONE_API_BASE.
      const API_BASE = process.env.RADIUMONE_API_BASE || "https://api-sandbox.radiumone.io/gateway";
      const accessToken = process.env.RADIUMONE_ACCESS_TOKEN;
      const transactionId = process.env.RADIUMONE_TRANSACTION_ID;

      async function inquireTransactionStatus() {
        const res = await fetch(`${API_BASE}/v1/transactions/${transactionId}/status`, {
          headers: { Authorization: `Bearer ${accessToken}` },
        });
        const payload = await res.json();
        if (!res.ok) {
          throw new Error(`status inquiry failed: ${payload.type ?? payload.code} (${res.status})`);
        }
        return payload; // branch on data.status
      }

      inquireTransactionStatus().then((r) => console.log(JSON.stringify(r, null, 2)));
      ```

      ```python Python theme={null}
      #!/usr/bin/env python3
      """Live acquirer status inquiry for a transaction (no new row written). Use
      this to recover after a timeout instead of guessing the outcome.
      """
      import json
      import os

      import requests

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


      def inquire_transaction_status() -> dict:
          transaction_id = os.environ["RADIUMONE_TRANSACTION_ID"]
          resp = requests.get(
              f"{API_BASE}/v1/transactions/{transaction_id}/status",
              headers={"Authorization": f"Bearer {os.environ.get('RADIUMONE_ACCESS_TOKEN', '')}"},
              timeout=30,
          )
          payload = resp.json()
          if not resp.ok:
              code = payload.get("type") or payload.get("code")
              raise RuntimeError(f"status inquiry failed: {code} ({resp.status_code})")
          return payload  # branch on data.status


      if __name__ == "__main__":
          print(json.dumps(inquire_transaction_status(), indent=2))
      ```
    </CodeGroup>
  </Step>

  <Step title="Key the outcome on data.success">
    `data.success` (a boolean) is the field to branch on. `data.status` (`"success"`/`"failed"`) is a convenience label derived purely from whether the acquirer's `response_code` is `"00"` — it doesn't consult the decline-code catalog the way `data.success` does, so in rare cases the two can disagree (an operator-catalogued approval on a non-`"00"` code reports `data.success: true` with `data.status: "failed"`). Never derive the outcome from `data.response_code` alone; that's the verbatim acquirer code, for display and reconciliation only.
  </Step>
</Steps>

## Response fields

| Field | Type | Meaning |
| - | - | - |
| `request_id` | string | The transaction's own idempotency key, echoed back. |
| `inquiry_type` | string | Always `"status"` for this endpoint. |
| `success` | boolean | **The field to key the outcome on.** `true` when the acquirer approved, or when an operator-catalogued decline classification approves the host's code. |
| `response_code` | string | Verbatim acquirer/switch response code — display and reconciliation only. |
| `status` | string | `"success"` or `"failed"` — a convenience label derived purely from `response_code == "00"`, ignoring the decline-code catalog. Usually matches `success`, but can disagree in the rare case above — key on `success`, not this field. This is **not** the transaction's lifecycle status (`AUTHORIZED`, `CAPTURED`, and so on); status inquiry writes nothing, so the stored transaction is untouched. |
| `message` | string \| null | Optional detail, when the acquirer supplies one. |
| `switch_request_id` | string \| null | Correlation ID from the payment switch, when available. |

## Relation to webhooks and replay

Status inquiry, webhooks, and replaying the same idempotency key are the three ways to learn a transaction's outcome — reach for whichever fits the moment:

* **Replay with the same `request_id`/`operation_id`** is the only way to recover a transaction `id` you never received — for example, a client-side timeout before the first response arrived. The replay returns the stored result, whatever it is.
* **Status inquiry** is the safest tool once you already have an `id` and want a live read against the acquirer. It's read-only, so calling it repeatedly is always safe, and it needs no idempotency key of its own.
* **Webhooks** push the eventual outcome to your server without polling. Prefer them for routine updates, and reserve status inquiry for on-demand recovery rather than scheduled polling.

See [Handle timeouts and unknown outcomes](/payments-api/handle-failures/timeouts-and-unknown-outcomes) for the full recovery walkthrough, and [Webhook event types](/payments-api/webhooks/event-types) for the events that carry the same outcome asynchronously.

## Errors

* `404` — no transaction with that `id` on your merchant account
* [`gateway:validation-error`](/payments-api/errors/payment-operation-errors#gateway-validation-error) — the transaction has no acquirer snapshot to query (very old or unrouted rows)

## Test your integration

See [Test your integration](/resources/test-your-integration#timeouts-and-retries) for simulated timeout and status-inquiry scenarios.

## Go-live notes

* Use status inquiry for recovery, not routine polling — prefer webhooks for updates you don't need on demand.
* Build the retry-with-same-key + status-inquiry path before you go live, not during your first production incident.
* Review the full [go-live checklist](/resources/go-live-checklist).

## Next steps

<Columns cols={2}>
  <Card title="Handle timeouts and unknown outcomes" icon="clock-alert" href="/payments-api/handle-failures/timeouts-and-unknown-outcomes">
    The full recovery walkthrough after a timed-out request.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/payments-api/webhooks/overview">
    Get transaction updates pushed to your server instead of polling.
  </Card>
</Columns>
