TRADOM PaymentDocs

Hosted Checkout

Redirect customers to a payment page hosted by TRADOM Payment

Hosted Checkout lets you accept stablecoin payments without building the payment UI yourself. Your backend creates an order and redirects the customer to the returned URL.

Start with the quickstart →

How it works

Merchant backend ── createOrder ──> TRADOM Payment
        │                                  │
        └── redirect to checkoutUrl ──────> Hosted Checkout
                                           │
                                  asset / network selection
                                  QR code and confirmation
                                           │
Merchant backend <── checkoutStatus ───────┘

Create a checkout

const checkout = await gatewayClient.gateway.createOrder({
  orderId: "order_12345",
  amount: 178.25,
  currency: "USD",
  buyerName: "Taro Yamada",
  buyerEmail: "taro@example.com",
  country: "JP",
  items: [{ name: "T-shirt", category: "apparel" }],
  returnUrl: "https://shop.example/thanks",
  cancelUrl: "https://shop.example/cart",
  mode: "live",
});
FieldRequiredDescription
orderIdYesYour order ID. Creation is idempotent for the same ID
amountYesA positive finite number in the currency's major unit
currencyNoJPY (the default when omitted) or USD
buyerEmail / country / itemsRecommendedUsed for compliance screening
buyerNameNoCustomer name
returnUrlStrongly recommendedDestination after payment
cancelUrlNoDestination after cancellation or screening rejection
modeNolive (default), testnet, or simulate. On staging (Fireblocks sandbox) live is coerced to testnet; read the effective mode from the response's mode

Handle the response

if (checkout.status === "ok") {
  return redirectTo(checkout.checkoutUrl);
}

// kyc_declined is also a successful API response.
return redirectTo(checkout.checkoutUrl);

kyc_declined is not an exception. Only network and validation errors throw a PaymentError.

An ok response echoes amount as a decimal string exactly as submitted and currency as normalized JPY or USD. On save, JPY is rounded to a whole number and USD to two decimals, so checkoutStatus returns the rounded value (e.g. "178" → "178.00"). Send whole yen for JPY and at most two decimals for USD.

currency: "USD" is available in production. JPY orders are quoted with a USD/JPY reference rate; USD orders use the stablecoin's 1:1 USD peg.

Check payment status

const status = await gatewayClient.gateway.checkoutStatus(checkoutToken);

checkoutStatus uses the public checkout token and does not send an API key. Do not trust the browser redirect alone. Store the association between your orderId and checkout token on your backend.

What to checkField
Canonical order amount and fiat currencystatus.amount / status.currency
Whether the full amount was receivedstatus.confirmed
Whether the deposit is shortstatus.underpaid (amounts in sentAmount / expectedAmount)
Deposit tx hash, amount, currency, networkstatus.txHash / paidAmount / paidCurrency / paidNetwork
Current processing stagestatus.state.state
Whether the state is terminalstatus.state.isTerminal
Underpayment or overpaymentstatus.state.matchStatus
Message shown to the customerstatus.message
Execution modestatus.mode
Testnet faucetsstatus.faucets

confirmed means "the full amount was received". An underpaid deposit yields confirmed: false together with underpaid: true (state.matchStatus: "underpaid"). Use underpaid to tell "no deposit yet" apart from "deposit received but short".

checkoutStatus is the same endpoint the Hosted Checkout page polls. It is not strictly read-only: it may attach an as-yet-unclaimed deposit to the order and record the underpaid classification (it never advances or cancels the order). message is null while the order is awaiting the deposit (M-5 is not shown).

See the status reference for every state.

Session and quote lifetime

  • Checkout session: 45 minutes after the first view (extendable once by 5 minutes via extendSession for the wallet check)
  • Deposit quote: 15 minutes
  • Quote refreshes: up to 2

Create a new checkout after the session expires. The session starts when the Hosted Checkout page is first opened; for an order driven purely through the SDK whose page was never opened, sessionExpired stays false.

Checkout controls

For a normal redirect integration, Hosted Checkout performs the following operations. Use the SDK methods for automated smoke tests or when controlling a token-scoped flow from your backend. These calls are authorized by the checkout token and do not send an API key.

const quote = await gatewayClient.gateway.selectAsset(checkoutToken, {
  token: "usdc",
  network: "ethereum",
});

const refreshed = await gatewayClient.gateway.refreshQuote(checkoutToken);
const accepted = await gatewayClient.gateway.acceptTos(checkoutToken);

selectAsset and refreshQuote return the fiat currency, deposit address, token amount, rate, chain metadata, mode, and faucets. JPY orders use a USD/JPY reference rate; USD orders use the stablecoin's 1:1 USD peg. A checkout can refresh its quote up to two times.

A simulate order can be completed after asset selection without moving funds.

const completed = await gatewayClient.gateway.simulateDeposit(checkoutToken);

simulateDeposit rejects live and testnet orders. See Test your integration for the complete flow.

Reference quote and wallet check

The helper endpoints used by the Hosted Checkout configure screen are also available from the SDK.

// "≈ amount" at the current rate (non-binding, cached ~12 s)
const ref = await gatewayClient.gateway.referenceQuote(checkoutToken);
if (ref.status === "ok") {
  console.log(ref.quotes.usdc?.amounts.ethereum); // "329.87"
}

// State of the buyer-wallet pre-check (small test transfer)
const verify = await gatewayClient.gateway.verifyStatus(checkoutToken);
// verify.screening: "pending" | "clear" | "received" | "blocked"

// One-time +5 minute session extension for the wallet check
const ext = await gatewayClient.gateway.extendSession(checkoutToken);
// ext.extended: true only on the first call

// Reset a blocked verification so the buyer can retry with another wallet (max 2 per order)
const reset = await gatewayClient.gateway.resetVerification(checkoutToken);
// reset.screening: "pending" | "not_required", reset.attemptsRemaining

resetVerification throws not_blocked (409) unless the current verdict is blocked and reset_limit_reached (409) once the resets are used up. After the session expires every call throws session_expired (409).

TRON and slippage verdicts

TRON / USDT can be selected when Tron payments are enabled for the merchant.

const verdict = await gatewayClient.gateway.slippageCheck(checkoutToken, {
  token: "usdt",
  network: "tron",
});

if (verdict.status === "exceeded") {
  return showAnotherAsset();
}

The verdict is ok, exceeded, skipped, or unavailable. The backend checks the verdict again when the asset is selected.

slippageCheck is available in production. TRON / USDT availability depends on merchant configuration (Tron payments enabled). slippageCheck accepts canonical network names only (ethereum / polygon / tron); the aliases selectAsset accepts (eth / pol / trx) return unsupported_asset.

Authentication

The SDK uses X-Api-Key by default. The REST API accepts either form:

X-Api-Key: gw_live_...
Authorization: Bearer gw_live_...

On this page