# Checkout Sessions API

> Create checkout sessions from your backend.

Canonical: https://stafiel.org/documentation/developer-integration/checkout-api
Version: v1.0.0

Create a checkout session from your backend when your customer is ready to pay.
The response contains a hosted checkout URL that you can redirect to, open in a
new tab, or pass to the Stafiel widget.

## Endpoint

POST /api/v1/checkout/sessions

## Request Fields

Field
Required
Default
Description

merchantId
Yes
None
Must match the merchant bound to the API key.

chainName
Yes
None
Mainnet chain label. See [Chain Labels](#chain-labels).

tokenSymbol
Yes
None
Use USDC or USDT, subject to the selected chain and merchant configuration.

amountUsd
Yes
None
Dollar-denominated checkout amount as a string. Use at most 2 decimal places, such as 49, 49.9, or 49.90; extra decimal places are rejected.

expiresIn
No
Merchant default
Payment window in seconds. The value must be inside the merchant's configured allowed range.

idempotencyKey
No
None
Recommended. Use your internal order ID so retries do not create duplicate checkout sessions.

metadata
No
None
Your own order reference, customer reference, return URL, or other non-sensitive metadata. See [Metadata Reserved Fields and Rules](#metadata-reserved-fields-and-rules).

## Chain Labels

Use these mainnet chainName values when creating live checkout sessions:

chainName
Chain ID
Description

eth
1
Ethereum mainnet for USDT and USDC payments.

base
8453
Base mainnet for lower-cost EVM payments.

bsc
56
BNB Smart Chain mainnet for EVM payments.

polygon
137
Polygon mainnet for EVM payments.

solana
101
Solana mainnet for SPL stablecoin payments.

tron
728126428
Tron mainnet for TRC20 stablecoin payments.

Available chains and tokens depend on merchant configuration.

## Request Example

The example includes the currently supported reserved metadata fields.

curl -X POST https://api.stafiel.com/api/v1/checkout/sessions \
  -H "X-API-Key: mk_live_your_api_key" \
  -H "X-App-Client: merchant-client" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "mch_your_merchant_id",
    "chainName": "base",
    "tokenSymbol": "USDC",
    "amountUsd": "49.00",
    "expiresIn": 1800,
    "idempotencyKey": "order_10001",
    "metadata": {
      "returnToUrl": "https://merchant.example.com/orders/10001",
      "productName": "Annual Pro Plan",
      "productDescription": "One-year subscription for the merchant workspace.",
      "quantity": "1",
      "unitLabel": "year",
      "customerReference": "CUS-8842"
    }
  }'

## Success Response

{
  "success": true,
  "data": {
    "orderId": "ord_your_order_id",
    "status": "awaiting_payment",
    "checkoutSessionUrl": "https://pay.stafiel.com/pay/ps_live_example",
    "expiresAt": "2026-05-19T12:00:00.000Z",
    "amountUsd": "49.00",
    "chainName": "base",
    "tokenSymbol": "USDC",
    "tokenAddress": "0x..."
  }
}

## Response Fields

Field
Type
Description

orderId
string
Stafiel order ID for later order, payment, refund, settlement, and document lookups.

status
string
Initial order status. New checkout sessions return awaiting_payment.

checkoutSessionUrl
string
Hosted checkout URL. Treat it as opaque and use it exactly as returned.

expiresAt
string
ISO 8601 timestamp when the checkout session expires.

amountUsd
string
Accepted checkout amount, stored with up to 2 decimal places.

chainName
string
Canonical public chain label used for the checkout session.

tokenSymbol
string
Token symbol selected for the checkout session.

tokenAddress
string
Token contract or mint address used for the selected chain.

Treat checkoutSessionUrl as opaque. Do not build payment URLs yourself.

## Idempotency Key

idempotencyKey provides short-window duplicate protection for checkout session
creation retries. A stable internal order ID is a good key because it maps one
merchant-side order attempt to one checkout creation attempt.

Rules:

- Use 1-128 visible ASCII characters.

- Reuse the same key when retrying the same request.

- Do not reuse the same key for a different checkout payload.

- If the same key is already being processed, or if the key is reused with a
conflicting payload, the API returns 409 CHECKOUT_SESSION_CREATE_FAILED.

- Do not use idempotency keys as a permanent order lookup mechanism.

## Metadata Reserved Fields and Rules

metadata is an optional JSON object for merchant business context, such as
your internal order ID or customer reference. Do not put secrets, private keys,
access tokens, full payment credentials, or unnecessary sensitive personal data
in metadata.

Stafiel currently interprets these reserved metadata fields for checkout return
behavior, hosted checkout display, and generated documents:

Field
Required
Default
Description

metadata.returnToUrl
No
None
Checkout return URL, used only when allowed by the merchant return URL policy.

metadata.productName
No
None
Product or service name for hosted checkout and documents.

metadata.productDescription
No
None
Short product or order description for hosted checkout and documents.

metadata.quantity
No
None
Product quantity for hosted checkout and documents.

metadata.unitLabel
No
None
Unit label after quantity, such as seat, month, or year.

General metadata rules:

- Use a flat object. Nested objects and arrays are ignored.

- Stafiel stores up to 20 accepted top-level fields, processed in request object
order. Invalid fields are ignored and do not count toward the limit.

- Keys must be 1-100 characters and may use ASCII letters, numbers, dots,
underscores, and hyphens.

- Values may be strings, finite numbers, booleans, or null. Objects, arrays,
invalid values, and unsupported value types are ignored.

- String values may be up to 1,000 characters and may contain letters, numbers,
punctuation, spaces, and line breaks.

metadata.returnToUrl rules:

- The value must be an absolute https:// URL.

- Unsafe or blocklisted URLs are rejected.

- If the URL is not allowed by merchant return URL policy, it will not be used.

## Error Responses

Error responses use this shape:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request"
  }
}

HTTP Status
Code
Meaning

400
CHECKOUT_SESSION_CREATE_FAILED / ORDER_EXPIRES_IN_OUT_OF_RANGE
Request is invalid, cannot create a session, or expiresIn is outside the allowed range.

401
AUTH_FAILED
API key is missing, invalid, or in the wrong mode.

403
NO_MERCHANT_ACCOUNT
Merchant account is required.

409
CHAIN_NOT_AVAILABLE / TOKEN_NOT_AVAILABLE / CHECKOUT_SESSION_CREATE_FAILED
Chain or token is unavailable, or the idempotency key is in progress or conflicting.

429
RATE_LIMIT_EXCEEDED
Too many requests. Retry after the indicated time.
