> For the complete documentation index, see [llms.txt](https://docs-swap.crypto-chief.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-swap.crypto-chief.com/guides/production-checklist.md).

# Production Checklist

## Production Checklist

The items that bite in production, in the order an integration meets them.

### The key

* **The key stays on your servers.** Your project UUID is in the request path, so the full URL spends your credits. Nothing with the key ships to a browser or an app — proxy through your backend if a client needs swaps. [Authentication](/getting-started/authentication.md)
* **Turn the project's domain or IP whitelist on** where your setup allows it: a leaked key with a whitelist is a smaller problem.
* **Put `X-Request-Id` in your logs.** Set your own id per call and log it with the response's `x-request-id`. It is the handle support will ask for. [Errors](/getting-started/errors.md)

### Quoting and building

* **A quote lives 30 seconds.** Build right after quoting, with `quote_id`, and rebuild after any long pause: `amount_out_min` is computed from fresh state. An expired `quote_id` gives a fresh search, not an error. [How a Swap Works](/getting-started/how-a-swap-works.md#quote-vs-build)
* **Compare the build's `amount_out_min` with the quote's** if you showed the quote to a customer: the build can be lower. Print `warnings`; they are free text for logs.
* **Every build is charged** (10,000 credits) and returns **fresh transactions**. Rebuild because a step asked for it, state went stale, or a deadline passed — never to poll. And never send transactions from two builds for the same step. [Billing](/getting-started/billing.md)
* **Read `simulation.status` before signing a `swap` step.** Strict integrations sign only on `passed`. [Simulation](/getting-started/how-a-swap-works.md#simulation)
* **Choose `approve_mode` deliberately.** `exact` (default) limits what a compromised router can take to the swap amount; `unlimited` is a standing permission. [Approve: Transaction](/api-reference/approve-transaction.md)

### Deadlines

* **EVM / TRON:** `deadline_seconds`, default 120, when the executor checks it on chain (`executor.onchain_deadline`).
* **Solana:** valid until `last_valid_block_height` — about 60–90 seconds. Sign immediately.
* **TON:** `validUntil` is the deadline; keep `deadline_seconds` at most 300 ([why](/getting-started/how-a-swap-works.md#deadlines-per-network)).
* **XRP Ledger:** `LastLedgerSequence` = validated ledger + 35 — about 120 seconds. Past it, rebuild.

### Executing

* **Steps in order, always.** `wait_for_confirmation: true` means the next signature waits for this step's confirmation.
* **`rebuild_after_previous: true` means do not sign.** Rebuild with the same parameters and continue with the new response's steps. If the rebuild still returns an `approve` for the same token, wait and rebuild; do not approve twice. [How a Swap Works](/getting-started/how-a-swap-works.md#executing-the-steps)
* **Non-atomic routes: keep every hash.** On every rebuild pass `executed_tx_hashes` (up to 16). On TRON a swap the chain does not show yet is recognised only by its hash. Handle `503 STATE_STALE` (retry later or pass the hash) and `400 INVALID_REQUEST` (the one-hour record expired: restart the remainder from the token the executed swap paid out). Stop rebuilding once the last swap of the deal confirmed: a further rebuild sells the input again. [Non-atomic routes](/getting-started/how-a-swap-works.md#non-atomic-routes)

### Retrying

* Retry `429` after about one second, and `502`, `503`, `504` with backoff. Never retry another `4xx` or a `500` unchanged. [Errors](/getting-started/errors.md)
* Know which retries are free: availability failures you cannot cause are refunded; validation and route failures (`400`, `422`) are real work and stay charged. [Billing](/getting-started/billing.md)

### Verifying the result on chain

The API's job ends at the unsigned transaction. The swap's result is on the chain:

* **EVM / TRON:** the transaction receipt — status, and the logs for the real amounts.
* **Solana:** the confirmed transaction's token-account balance changes.
* **TON:** the incoming messages after yours — the output arrives there; a rejected swap returns the input.
* **XRP Ledger:** `delivered_amount` of the validated transaction (and, for a `Batch`, both inner payments — the outer result does not show them).

### Testing

Develop on a testnet first — `ETH_SEPOLIA`, `BSC_TESTNET`, `ARBITRUM_SEPOLIA`, `OPTIMISM_SEPOLIA`, `AVAX_TESTNET`, `TRON_NILE`, `XRP_TESTNET` are enabled. Same requests, same shapes, valueless coins. Check `ready` in [`/v1/networks`](/api-reference/networks.md) before a test run: a network that did not start answers `503 NETWORK_UNAVAILABLE`, one whose state lags `503 STATE_STALE`.
