# CryptoExchanger API — for AI agents and programs Non-custodial, no-KYC instant crypto swaps over a simple REST API. You never hand us your keys or funds: you send from your own wallet to a deposit address we return, and we route the swap to the recipient you name. Machine-readable spec (OpenAPI 3.1): https://cryptoexchanger.co/openapi.json Human docs: https://cryptoexchanger.co/docs ## Flow 1. GET https://cryptoexchanger.co/api/v1/estimate?from=BTC&to=ETH&amount=0.05 -> quote (rate, min, max, amount out). No key. 2. POST https://cryptoexchanger.co/api/v1/exchange (key required) -> returns payinAddress + exact amount to send (+ memo/tag if any). 3. Send exactly expectedFromAmount to payinAddress from your wallet. 4. GET https://cryptoexchanger.co/api/v1/order/{id} (key) -> poll status: waiting -> confirming -> exchanging -> sending -> finished. ## Auth Get a key (self-serve): https://cryptoexchanger.co/docs/keys — or POST https://cryptoexchanger.co/api/portal/keys {email,label,mode}. Send it as a header: Authorization: Bearer cx_live_... (or X-API-Key: cx_live_...) Use a cx_test_ key for the sandbox (simulated swaps, no real money) — identical request/response shapes. Send an Idempotency-Key header on POST /exchange so a retried request replays the same order (never a duplicate). Use 8-64 letters, digits, underscores or hyphens. Keep the SAME key for an unchanged action across restarts. A completed key replays its original order even after expiry; it never becomes a fresh create. On 503 creation_pending, creation_uncertain or creation_safety_unavailable, retain that key and retry it only; check Orders or contact support before starting another order. Unknown allocation outcomes fail closed. ## Multi-network coins USDT, USDC and some tokens exist on several chains. Pass fromNetwork/toNetwork (each coin's `network` from /currencies); omit it and you get code=network_required listing the valid networks to choose from. ## Destination memo / tag Some coins (HBAR, ATOM, STX, USDC-on-Algorand…) need a memo/tag on the PAYOUT. If the `to` coin's `hasExtraId` is true in /currencies, collect that tag from the user and send it as `extraId` in the /exchange body — the payout is unrecoverable without it. (The DEPOSIT memo, when required, is returned as order.payinExtraId — include it when you send the deposit.) ## Refund memo / tag If the refund wallet requires routing metadata, send refundExtraId on BOTH estimate and exchange. It is an optional string up to 128 characters; surrounding whitespace is trimmed. XRP uses ASCII uint32 0..4294967295. Only configured routes with verified refund-memo support can quote/create it; unsupported routes are excluded. The receipt returns order.refundExtraId. /api/config refundMemoSupported describes configured capability, not a guarantee every pair is available. Never omit a required tag; use a personal wallet if no compatible route exists. ## Address validation We validate the payout/refund address chain server-side and reject a wrong-chain address before minting (code=invalid_address). Still validate client-side too: this API is non-custodial, so a valid-but-wrong address you sign for is not recoverable. ## Endpoints GET /api/v1/currencies list supported coins + networks GET /api/v1/estimate?from=&to=&amount= quote a swap (rate, min, max) GET /api/v1/check?from=&to= is a pair supported (no amount) POST /api/v1/exchange create an order -> deposit address (key) GET /api/v1/order/{id} order status (key) ## Errors JSON {error, code}. Codes: below_min, above_max, unsupported_currency, unsupported_network, network_required, invalid_address, invalid_request, no_route, idempotency_mismatch, invalid_idempotency_key, invalid_refund_extra_id, refund_memo_unsupported, creation_pending, creation_uncertain, creation_safety_unavailable, unauthorized, rate_limited, not_found. On 429 the response carries Retry-After and X-RateLimit-Remaining headers — respect them. ## Optional: webhooks POST https://cryptoexchanger.co/api/portal/keys/webhook {url} (key) registers a URL; we POST order.updated on every status change with header X-CX-Signature: sha256=HMAC-SHA256(signingSecret, rawBody). Verify it. Example: curl "https://cryptoexchanger.co/api/v1/estimate?from=BTC&to=ETH&amount=0.05"