# CheckoutRail integration guide

CheckoutRail creates hosted cryptocurrency checkouts for merchant orders.

## Safe server-side flow

1. Store the CheckoutRail secret key only on your server.
2. POST /v1/invoices with amount, currency and your order reference.
3. Save the returned invoice id with your order.
4. Redirect the customer to checkout_url.
5. Receive invoice.paid on your webhook endpoint.
6. Verify CheckoutRail-Signature against the exact raw request body before fulfilling the order.

## Environments

- Sandbox keys start with cr_test_sk_. Use them for test invoices and simulated transfers.
- Live keys start with cr_live_sk_. Live access requires merchant approval and platform activation.
- Sandbox stays available after Live is enabled.
- Test and Live webhook URLs and signing secrets are separate.
- Sandbox payment methods include Ethereum (ETH and USDT), Bitcoin, and
  Litecoin. These expansion rails are not available with Live keys until
  their custody release gates pass.
- USDC, DAI, LINK, WBTC, UNI and AAVE on Ethereum support Sandbox payments
  and withdrawals. Testnet and Live require separate per-token custody activation.
  They remain in the received currency; automatic conversion to USDT is not available.
- Discover available assets with GET /v1/payment-methods. Do not hardcode a
  currency list. Each method includes its network, decimals, capabilities,
  and simulation_only flag. The flag describes execution support, not price.
- Simulated USDC and DAI quotes use a 1 USD test fixture; LINK uses 20 USD.
  WBTC uses 100,000 USD, UNI 10 USD, and AAVE 200 USD.
  These are not market prices. Confirmed funds remain in the received currency.
- GET /v1/balances returns asset_id and available_base_units in both environments.

## Create an invoice

The current founder-test minimum invoice amount is 1.00 in USD or USDT.

    curl https://api.checkoutrail.com/v1/invoices \
      -H "Authorization: Bearer $CHECKOUTRAIL_SECRET_KEY" \
      -H "Idempotency-Key: order_5041" \
      -H "Content-Type: application/json" \
      -d '{"amount":"125.00","currency":"USD","reference":"order_5041"}'

Never create invoices from browser code. Never paste a Live secret key into an AI chat or commit it to source control.

## Withdrawals

POST /v1/withdrawals requires withdrawals:write and an Idempotency-Key.
Pass amount as a decimal string, network_id, address and optionally asset_id.
For example: {"amount":"10.123456","network_id":"ethereum","asset_id":"ethereum:usdc","address":"0x..."}.
Omitting asset_id preserves the network default (USDT on Ethereum).
Never reuse an idempotency key with a different coin, amount or address.
The amount includes the network cost. Only that asset's balance is reserved;
operator rejection releases it. A broadcast transaction is not a completed payout.
The authenticated dashboard additionally requires an authenticator code.

## Webhook signature

The CheckoutRail-Signature header contains t=<unix timestamp>,v1=<HMAC SHA-256>.
Sign the string "<timestamp>.<raw body>" with the environment's whsec_ signing secret. Reject requests older than five minutes. Return HTTP 2xx only after the event is safely stored. Event ids can be delivered more than once, so processing must be idempotent.

Events: invoice.paid, invoice.expired, withdrawal.updated.

Canonical API contract: /openapi.json
