{"openapi":"3.1.0","info":{"title":"Kotova X API","version":"1.0.0","summary":"Quotes, orders and the catalog of Kotova X.","description":"Quote and create crypto swaps at the sources Kotova X routes to — the parties that execute each swap — with the rates, ranking and terms of app.kotova.io.\n\n**Base URL** `https://api.kotova.io/x/v1`. JSON everywhere (UTF-8, snake_case), except the XML rates feed.\n\n**Authentication.** Keyed operations take `Authorization: Bearer ktv_sk_…`, the secret of the API key you create on your Kotova account page. Keep it on your server. Keyless operations (service, catalog, rates feed) need no key and ignore one; send none, so the CDN can answer them.\n\n**Conventions.**\n- Amounts are decimal strings: no exponent, no trailing zeros, at most min(network decimals, 12) fractional digits. What the end user sends is rounded up, what they receive is rounded down.\n- Timestamps are ISO-8601 UTC with `Z`.\n- Identifiers: `currency` is the ticker (`BTC`), `network` the network code (`btc`, `trx`), a source its `slug`. Numeric ids are never exposed.\n- A single resource is the object itself; lists are `{data, has_more, next_cursor}` (catalog lists add `catalog_version` and `updated_at`).\n- Ignore response fields you do not know: fields are added without notice.\n- Unknown body fields and unknown or repeated query parameters are a 400 `invalid_request`, never silently ignored; so are empty query segments (`?&`) on keyless operations.\n- POST bodies need `Content-Type: application/json` (else 415) and at most 16 KB (else 413).\n- Every response carries `X-Request-Id`; quote it to support (api@kotova.io).\n- An unsupported method is a 405 `method_not_allowed` with `Allow`. HEAD works on every keyless GET.\n\n**Rate limits.** Each account has a budget of weight units per 60-second window (default 250; higher limits on request). POST /orders weighs 50, every other keyed call 1 (`x-kotova-weight`); a refused call costs nothing, and a replay or an error before the source was contacted costs 1. Keyed responses carry `X-Kotova-Weight`, `RateLimit-Policy`, `RateLimit`, `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`; a 429 adds `Retry-After`. Quotes that ask a source live also count against max(30, limit/8) per minute: a cache miss, or a cached quote that still has to ask a source live (e.g. a source that prices per end user when `end_user_ip` is sent). Orders are capped per account: open unfunded orders at 20 × limit/250 and orders created in 24 hours at 100 × limit/250 (429 `order_cap_reached`). These figures are rounded down, and each cap is at least 1. Keyless calls that reach the server are limited to 120 per minute per IP; the rates feed has its own allowance of the same size.\n\n**Errors.** Every non-2xx answer is `{\"error\": {\"code\", \"message\", \"request_id\", \"details\"?, \"doc_url\"}}`. Branch on `code` — stable, with new codes added over time (fall back on the HTTP status) — never on `message`.\n\n**Warnings.** A 2xx body may carry `warnings[]`: non-fatal notes with an extensible `code`.\n\n**Attribution.** Quotes, orders and GET /sources carry the `provider` block (Kotova X) and the `source` block with the notice the end user must see before an order is created. A quote's `fallback_sources` carry their notices too: the order may be placed with one of them, so show them as well before the order — or send `retry_next_best_source: false` with the order. https://docs.kotova.io/x/api/display-requirements.\n\n**Browsers.** Keyless operations answer `Access-Control-Allow-Origin: *`. Keyed operations answer CORS only to an allowlist (the Kotova docs console): call them from your server.\n\n**Versioning.** Additive changes — fields, operations, error and warning codes, values of extensible enums — ship at any time. Breaking changes, including a new value in a closed enum (order `status`, `rate_type`, `amount_type`), come only as /x/v2, announced at least 30 days ahead (Deprecation and Sunset headers, e-mail, changelog: https://docs.kotova.io/x/api/changelog).","termsOfService":"https://kotova.io/terms/api","contact":{"name":"Kotova X API support","email":"api@kotova.io","url":"https://docs.kotova.io/x/api"}},"servers":[{"url":"https://api.kotova.io/x/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Service","description":"Index, health and this document. No key."},{"name":"Catalog","description":"Currencies, networks, sources and pairs. No key; CDN-cached."},{"name":"Rates feed","description":"Rates in the BestChange XML format, for rate monitors. No key."},{"name":"Quotes","description":"The best source for a swap, and a quote_id to order from."},{"name":"Orders","description":"Create orders from quotes and track them."},{"name":"Utilities","description":"Helpers that call no source."},{"name":"Account","description":"Your key and limits."}],"externalDocs":{"description":"Kotova X API documentation","url":"https://docs.kotova.io/x/api"},"paths":{"/":{"get":{"operationId":"getIndex","tags":["Service"],"summary":"API index","description":"Links to the documentation, this OpenAPI document, the changelog and the health check. The canonical URL is `https://api.kotova.io/x/v1`, without a trailing slash: `/x/v1/` only answers a 308 redirect to it.","security":[],"responses":{"200":{"description":"The index.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Index"},"example":{"name":"Kotova X API","version":"v1","docs_url":"https://docs.kotova.io/x/api","openapi_url":"https://api.kotova.io/x/v1/openapi.json","changelog_url":"https://docs.kotova.io/x/api/changelog","health_url":"https://api.kotova.io/x/v1/health"}}}},"304":{"$ref":"#/components/responses/NotModified"},"400":{"$ref":"#/components/responses/KeylessInvalidRequest"},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"$ref":"#/components/responses/KeylessServiceUnavailable"}}}},"/health":{"get":{"operationId":"getHealth","tags":["Service"],"summary":"Health check","description":"Liveness of the API: 200 while it can answer (with `status: degraded` when the catalog is stale), 503 when its storage or catalog is unavailable or the API is switched off. Cached for 10 s; no ETag.","security":[],"responses":{"200":{"description":"The API answers.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"},"example":{"status":"ok","api_version":"v1","time":"2026-11-10T10:15:04Z","catalog_version":"394da0f044c4","mock":false}}}},"400":{"$ref":"#/components/responses/KeylessInvalidRequest"},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"description":"The API cannot serve requests right now (`details.reason`: `storage_unavailable`, `catalog_missing`, `disabled`, …).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"storage_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Retry shortly.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"storage_unavailable"},"doc_url":"https://docs.kotova.io/x/api/errors#service_unavailable"}}},"catalog_missing":{"value":{"error":{"code":"service_unavailable","message":"The currency catalog is temporarily unavailable.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"catalog_missing"},"doc_url":"https://docs.kotova.io/x/api/errors#service_unavailable"}}}}}}}}}},"/openapi.json":{"get":{"operationId":"getOpenApi","tags":["Service"],"summary":"This OpenAPI document","description":"The OpenAPI 3.1 description of /x/v1 — the API's single source of truth.","security":[],"responses":{"200":{"description":"The OpenAPI document.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}},"content":{"application/json":{"schema":{"type":"object","description":"An OpenAPI 3.1 document."}}}},"304":{"$ref":"#/components/responses/NotModified"},"400":{"$ref":"#/components/responses/KeylessInvalidRequest"},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"$ref":"#/components/responses/KeylessServiceUnavailable"}}}},"/currencies":{"get":{"operationId":"getCurrencies","tags":["Catalog"],"summary":"List currencies and networks","description":"Every currency the API can swap, with each network it can be sent (`send`) or received (`receive`) on and the sources serving each direction. Takes no parameters: apply source exclusions client-side with `send_sources` / `receive_sources`. CDN-cached for 60 s with a weak ETag (send If-None-Match for a 304).","security":[],"responses":{"200":{"description":"The currency list.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrencyList"},"example":{"data":[{"currency":"BTC","name":"Bitcoin","type":"cryptocurrency","icon":{"url":"https://cdn.kotova.io/images/currencies/BTC.svg","fallback_url":"https://assets.kotova.io/images/currencies/BTC.svg"},"aliases":[],"networks":[{"network":"btc","network_name":"Bitcoin","name":"Bitcoin","ticker":"BTC","contract_address":null,"token_standard":null,"decimals":8,"memo":{"supported":false,"label":null},"address_format":"standard","icon":{"url":"https://cdn.kotova.io/images/currencies/BTC.svg","fallback_url":"https://assets.kotova.io/images/currencies/BTC.svg"},"send":true,"receive":true,"send_sources":["sideshift","chainflip","changenow","ffio"],"receive_sources":["sideshift","chainflip","changenow","ffio"]}]},{"currency":"USDT","name":"Tether","type":"stablecoin","icon":{"url":"https://cdn.kotova.io/images/currencies/USDT.svg","fallback_url":"https://assets.kotova.io/images/currencies/USDT.svg"},"aliases":["USDT0"],"networks":[{"network":"trx","network_name":"TRON","name":"Tether (TRC20)","ticker":"USDT","contract_address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","token_standard":"TRC20","decimals":6,"memo":{"supported":false,"label":null},"address_format":"standard","icon":{"url":"https://cdn.kotova.io/images/tokens/USDT-TRX.svg","fallback_url":"https://assets.kotova.io/images/tokens/USDT-TRX.svg"},"send":true,"receive":true,"send_sources":["sideshift","changenow","ffio"],"receive_sources":["sideshift","changenow","ffio"]}]}],"has_more":false,"next_cursor":null,"catalog_version":"394da0f044c4","updated_at":"2026-11-10T07:00:52Z"}}}},"304":{"$ref":"#/components/responses/NotModified"},"400":{"$ref":"#/components/responses/KeylessInvalidRequest"},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"$ref":"#/components/responses/KeylessServiceUnavailable"}}}},"/networks":{"get":{"operationId":"getNetworks","tags":["Catalog"],"summary":"List networks","description":"Every network with at least one usable currency: memo support, address format, EVM chain id and an explorer link template. No parameters. CDN-cached for 60 s with a weak ETag.","security":[],"responses":{"200":{"description":"The network list.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NetworkList"},"example":{"data":[{"network":"btc","name":"Bitcoin","symbol":"BTC","family":"utxo","icon":{"url":"https://cdn.kotova.io/images/chains/btc.svg","fallback_url":"https://assets.kotova.io/images/chains/btc.svg"},"memo":{"supported":false,"label":null},"address_format":"standard","evm_chain_id":null,"explorer_tx_url_template":"https://mempool.space/tx/{hash}"},{"network":"eth","name":"Ethereum","symbol":"ETH","family":"evm","icon":{"url":"https://cdn.kotova.io/images/chains/eth.svg","fallback_url":"https://assets.kotova.io/images/chains/eth.svg"},"memo":{"supported":false,"label":null},"address_format":"standard","evm_chain_id":1,"explorer_tx_url_template":"https://etherscan.io/tx/{hash}"},{"network":"xrp","name":"XRP Ledger","symbol":"XRP","family":"other","icon":{"url":"https://cdn.kotova.io/images/chains/xrp.svg","fallback_url":"https://assets.kotova.io/images/chains/xrp.svg"},"memo":{"supported":true,"label":"Destination Tag"},"address_format":"standard","evm_chain_id":null,"explorer_tx_url_template":"https://xrpscan.com/tx/{hash}"}],"has_more":false,"next_cursor":null,"catalog_version":"394da0f044c4","updated_at":"2026-11-10T07:00:52Z"}}}},"304":{"$ref":"#/components/responses/NotModified"},"400":{"$ref":"#/components/responses/KeylessInvalidRequest"},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"$ref":"#/components/responses/KeylessServiceUnavailable"}}}},"/sources":{"get":{"operationId":"getSources","tags":["Catalog"],"summary":"List sources","description":"The sources the API routes swaps to, with their rules, refund-address policy (`refund_address`: when one is required; `refund_address_forwarding`: what an order's refund address is used for there) and the notice to show in `lang`, plus the Kotova X `provider` block and the display requirements. A source that is temporarily not used is listed with `status: unavailable`. CDN-cached for 60 s with a weak ETag.","security":[],"parameters":[{"$ref":"#/components/parameters/Lang"}],"responses":{"200":{"description":"The sources.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceList"},"example":{"provider":{"name":"Kotova X","icon":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon.svg","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon.svg"},"icon_png":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon-256.png","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon-256.png"},"website_url":"https://app.kotova.io"},"attribution":{"provider_display_required":true,"source_notice_required_before_order":true,"docs_url":"https://docs.kotova.io/x/api/display-requirements"},"data":[{"slug":"sideshift","name":"SideShift","kind":"centralized","status":"active","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_sideshift.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_sideshift.svg"},"terms_url":"https://sideshift.ai/legal","rate_types":["fixed","variable"],"refund_address":"optional","refund_address_forwarding":"at_creation","requires_end_user_ip":true,"freeze_protection":false,"display_order":1,"notice":{"text":"The exchange service is provided by SideShift. Creating an order confirms your agreement with the SideShift rules.","link_text":"SideShift rules","link_url":"https://sideshift.ai/legal","lang":"en"}},{"slug":"chainflip","name":"Chainflip","kind":"decentralized","status":"active","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_chainflip.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_chainflip.svg"},"terms_url":null,"rate_types":["variable"],"refund_address":"required","refund_address_forwarding":"at_creation","requires_end_user_ip":false,"freeze_protection":true,"display_order":2,"notice":{"text":"The exchange service is provided by Chainflip. Creating an order confirms your agreement with the Kotova Terms of Service.","link_text":"Kotova Terms of Service","link_url":"https://kotova.io/terms/service?lang=en","lang":"en"}}],"has_more":false,"next_cursor":null,"catalog_version":"394da0f044c4","updated_at":"2026-11-10T07:00:52Z","warnings":[]}}}},"304":{"$ref":"#/components/responses/NotModified"},"400":{"$ref":"#/components/responses/KeylessInvalidRequest"},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"$ref":"#/components/responses/KeylessServiceUnavailable"}}}},"/pairs":{"get":{"operationId":"getPairs","tags":["Catalog"],"summary":"What a currency can be swapped into (or from)","description":"Give one side or both: `from` + `from_network`, `to` + `to_network`. A side given halfway is a 400 for its missing half; neither side is a 400 `from_or_to_required` (there is no all-pairs list).\n\n- both sides: that pair, when a source serves it (else an empty list);\n- `from` only: every leg it can be swapped into;\n- `to` only: every leg that can be swapped into it.\n\nPairs carry no limits — quotes do. CDN-cached for 60 s with a weak ETag.","security":[],"parameters":[{"name":"from","in":"query","required":false,"description":"Currency sent.","schema":{"$ref":"#/components/schemas/CurrencyId"},"example":"BTC"},{"name":"from_network","in":"query","required":false,"description":"Network of `from`.","schema":{"$ref":"#/components/schemas/NetworkId"},"example":"btc"},{"name":"to","in":"query","required":false,"description":"Currency received.","schema":{"$ref":"#/components/schemas/CurrencyId"},"example":"USDT"},{"name":"to_network","in":"query","required":false,"description":"Network of `to`.","schema":{"$ref":"#/components/schemas/NetworkId"},"example":"trx"}],"responses":{"200":{"description":"The pairs.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PairList"},"example":{"data":[{"from":{"currency":"BTC","network":"btc"},"to":{"currency":"USDT","network":"trx"},"rate_types":["fixed","variable"],"sources":["sideshift","changenow","ffio"]}],"has_more":false,"next_cursor":null,"catalog_version":"394da0f044c4","updated_at":"2026-11-10T07:00:52Z","warnings":[]}}}},"304":{"$ref":"#/components/responses/NotModified"},"400":{"description":"No side, a side given halfway, or an invalid identifier.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"from_or_to_required":{"value":{"error":{"code":"invalid_request","message":"Give from + from_network, to + to_network, or both.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"from","reason":"from_or_to_required"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"required":{"value":{"error":{"code":"invalid_request","message":"from_network is required with from.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"from_network","reason":"required"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}}}},"422":{"description":"A leg is unknown, not usable in its direction, or both legs are the same.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unknown_currency":{"value":{"error":{"code":"unknown_currency","message":"FOO on network btc is not in the catalog.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"side":"from","currency":"FOO","network":"btc"},"doc_url":"https://docs.kotova.io/x/api/errors#unknown_currency"}}},"currency_unavailable":{"value":{"error":{"code":"currency_unavailable","message":"BTC on network lightning cannot be received right now.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"side":"to","currency":"BTC","network":"lightning"},"doc_url":"https://docs.kotova.io/x/api/errors#currency_unavailable"}}},"same_currency":{"value":{"error":{"code":"same_currency","message":"The currency and network to send and to receive are the same.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"currency":"BTC","network":"btc"},"doc_url":"https://docs.kotova.io/x/api/errors#same_currency"}}}}}}},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"$ref":"#/components/responses/KeylessServiceUnavailable"}}}},"/rates/{file}":{"get":{"operationId":"getRatesXml","tags":["Rates feed"],"summary":"Rates feed (BestChange XML)","description":"The rates Kotova X can execute right now in the BestChange XML format, for rate monitors: `variable.xml` (variable rates) and `fixed.xml` (fixed rates).\n\nOne `<item>` per line, sorted by (from, to): `from`, `to`, `in` (always 1), `out`, `amount` (reserve), `minamount`, `maxamount`, optional `tofee`, optional `param`. Numbers are plain decimals (no exponent); currency codes are BestChange codes. When no input is fresh the feed is the valid empty document `<rates></rates>` with `X-Kotova-Feed-Status: degraded` — never stale rates.\n\nTakes no query string at all (any → 400). CDN-cached for 10 s; strong ETag and Last-Modified (304 on If-None-Match or If-Modified-Since). Calls that reach the server are limited to 120 per minute per IP, except BestChange's monitoring robots. A feed that is switched off answers 404.","security":[],"parameters":[{"name":"file","in":"path","required":true,"description":"`variable.xml` or `fixed.xml`.","schema":{"type":"string","enum":["variable.xml","fixed.xml"]},"example":"variable.xml"}],"responses":{"200":{"description":"The feed.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/RatesETag"},"Last-Modified":{"$ref":"#/components/headers/Last-Modified"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"X-Kotova-Feed-Status":{"$ref":"#/components/headers/X-Kotova-Feed-Status"},"X-Kotova-Feed-Sources":{"$ref":"#/components/headers/X-Kotova-Feed-Sources"},"X-Kotova-Feed-Generated-At":{"$ref":"#/components/headers/X-Kotova-Feed-Generated-At"}},"content":{"application/xml":{"schema":{"type":"string","description":"BestChange <rates> document."},"example":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rates>\n<item><from>BTC</from><to>USDTTRC20</to><in>1</in><out>68021.33412</out><amount>412000.5</amount><minamount>0.00092</minamount><maxamount>1.5</maxamount><tofee>0.1</tofee></item>\n<item><from>ETH</from><to>BTC</to><in>1</in><out>0.0361</out><amount>12.5</amount><minamount>0.01</minamount><maxamount>40</maxamount></item>\n<item><from>XMR</from><to>BTC</to><in>1</in><out>0.002511873</out><amount>18.5</amount><minamount>0.25</minamount><maxamount>310</maxamount><tofee>0.00012</tofee><param>manual</param></item>\n</rates>\n"}}},"304":{"description":"Not modified (If-None-Match or If-Modified-Since). No body.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/RatesETag"},"Last-Modified":{"$ref":"#/components/headers/Last-Modified"},"X-Kotova-Feed-Status":{"$ref":"#/components/headers/X-Kotova-Feed-Status"}}},"400":{"description":"A query string was sent.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"Unknown query parameter \"t\".","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"t","reason":"unknown_parameter"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}},"404":{"description":"Unknown file, or the feed is switched off.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"No such endpoint.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","doc_url":"https://docs.kotova.io/x/api/errors#not_found"}}}}},"429":{"$ref":"#/components/responses/KeylessRateLimited"},"503":{"$ref":"#/components/responses/KeylessServiceUnavailable"}}}},"/quote":{"post":{"operationId":"createQuote","tags":["Quotes"],"summary":"Get a quote","x-kotova-weight":1,"description":"The best source for a pair, amount and rate type under your filters — the same engine and ranking as app.kotova.io (`amount_type: from`: the largest `to.amount`; `to`: the smallest `from.amount`; ties by display order, then name). The answer carries a single-use `quote_id` for POST /orders: an order from it is placed at the quoted source or, unless the order sends `retry_next_best_source: false`, at the first of its `fallback_sources` that can; the end user must see their notices first.\n\nA quote pins its sources and the pair; it does not lock a rate. The order's own amounts are canonical. Quotes are served from a shared cache for up to 30 s (fixed) or 60 s (variable) (`X-Kotova-Quote-Cache: hit`); quotes that ask the sources count against the fan-out allowance (429 `details.reason: fanout`).\n\nWithout a quote: 422 `amount_below_min` / `amount_above_max` with the bounds, 503 `sources_unavailable` when sources could not be reached (retry after 10 s), 422 `pair_unavailable`, or 422 `no_source_available` with the filter reasons.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"},"example":{"from":{"currency":"BTC","network":"btc"},"to":{"currency":"USDT","network":"trx"},"amount":"0.05","amount_type":"from","rate_type":"variable","end_user_ip":"93.184.216.34","lang":"en"}}}},"responses":{"200":{"description":"The quote.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Kotova-Quote-Cache":{"$ref":"#/components/headers/X-Kotova-Quote-Cache"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"},"examples":{"with_end_user_ip":{"summary":"end_user_ip sent","value":{"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","created_at":"2026-11-10T10:15:04Z","expires_at":"2026-11-10T10:17:03Z","rate_type":"variable","amount_type":"from","from":{"currency":"BTC","network":"btc","amount":"0.05"},"to":{"currency":"USDT","network":"trx","amount":"3389.8"},"rate":"67796","limits":{"min_from_amount":"0.00029412","max_from_amount":"0.73529411"},"estimated_duration_seconds":1500,"requirements":{"refund_address":"optional","to_memo":"not_supported","refund_memo":"not_supported"},"filters":{"exclude_sources":[],"freeze_protection":false,"can_provide_refund_address":true,"end_user_ip_provided":true},"provider":{"name":"Kotova X","icon":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon.svg","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon.svg"},"icon_png":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon-256.png","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon-256.png"},"website_url":"https://app.kotova.io"},"source":{"slug":"sideshift","name":"SideShift","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_sideshift.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_sideshift.svg"},"terms_url":"https://sideshift.ai/legal","notice":{"text":"The exchange service is provided by SideShift. Creating an order confirms your agreement with the SideShift rules.","link_text":"SideShift rules","link_url":"https://sideshift.ai/legal","lang":"en"},"refund_address_forwarding":"at_creation"},"fallback_sources":[{"source":{"slug":"changenow","name":"ChangeNOW","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_changenow.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_changenow.svg"},"terms_url":"https://changenow.io/terms-of-use","notice":{"text":"The exchange service is provided by ChangeNOW. Creating an order confirms your agreement with the ChangeNOW rules.","link_text":"ChangeNOW rules","link_url":"https://changenow.io/terms-of-use","lang":"en"},"refund_address_forwarding":"at_creation"},"from":{"amount":"0.05"},"to":{"amount":"3376.2"},"requirements":{"refund_address":"optional"}},{"source":{"slug":"changelly","name":"Changelly","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_changelly.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_changelly.svg"},"terms_url":"https://changelly.com/terms-of-use","notice":{"text":"The exchange service is provided by Changelly. Creating an order confirms your agreement with the Changelly rules.","link_text":"Changelly rules","link_url":"https://changelly.com/terms-of-use","lang":"en"},"refund_address_forwarding":"at_creation"},"from":{"amount":"0.05"},"to":{"amount":"3371.45"},"requirements":{"refund_address":"optional"}}],"warnings":[]}},"without_end_user_ip":{"summary":"end_user_ip not sent: sources that need it are skipped","value":{"quote_id":"q_8Hn2KwQ4vT7cLm1Zx9RbYe","created_at":"2026-11-10T10:15:04Z","expires_at":"2026-11-10T10:17:03Z","rate_type":"variable","amount_type":"from","from":{"currency":"BTC","network":"btc","amount":"0.05"},"to":{"currency":"USDT","network":"trx","amount":"3376.2"},"rate":"67524","limits":{"min_from_amount":"0.00029412","max_from_amount":"0.73529411"},"estimated_duration_seconds":1200,"requirements":{"refund_address":"optional","to_memo":"not_supported","refund_memo":"not_supported"},"filters":{"exclude_sources":[],"freeze_protection":false,"can_provide_refund_address":true,"end_user_ip_provided":false},"provider":{"name":"Kotova X","icon":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon.svg","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon.svg"},"icon_png":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon-256.png","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon-256.png"},"website_url":"https://app.kotova.io"},"source":{"slug":"changenow","name":"ChangeNOW","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_changenow.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_changenow.svg"},"terms_url":"https://changenow.io/terms-of-use","notice":{"text":"The exchange service is provided by ChangeNOW. Creating an order confirms your agreement with the ChangeNOW rules.","link_text":"ChangeNOW rules","link_url":"https://changenow.io/terms-of-use","lang":"en"},"refund_address_forwarding":"at_creation"},"fallback_sources":[{"source":{"slug":"changelly","name":"Changelly","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_changelly.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_changelly.svg"},"terms_url":"https://changelly.com/terms-of-use","notice":{"text":"The exchange service is provided by Changelly. Creating an order confirms your agreement with the Changelly rules.","link_text":"Changelly rules","link_url":"https://changelly.com/terms-of-use","lang":"en"},"refund_address_forwarding":"at_creation"},"from":{"amount":"0.05"},"to":{"amount":"3371.45"},"requirements":{"refund_address":"optional"}}],"warnings":[{"code":"end_user_ip_missing","message":"Sources that quote per end user were skipped because end_user_ip was not sent; sending it may improve the rate.","sources":["sideshift"]}]}}}}}},"400":{"description":"Malformed request (`details.field`, `details.reason`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"required":{"value":{"error":{"code":"invalid_request","message":"rate_type is required (fixed or variable).","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"rate_type","reason":"required"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"too_many_decimals":{"value":{"error":{"code":"invalid_request","message":"amount has more than 8 decimal places for this currency and network.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"amount","reason":"too_many_decimals","max_fraction_digits":8},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"not_public_unicast":{"value":{"error":{"code":"invalid_request","message":"end_user_ip must be the end user's public IPv4 or IPv6 address.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"end_user_ip","reason":"not_public_unicast"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/AffiliateInactive"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"description":"No quote for this request.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"amount_below_min":{"value":{"error":{"code":"amount_below_min","message":"The amount is below the minimum of every available source.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"min_from_amount":"0.00029412","max_from_amount":"0.73529411","currency":"BTC","network":"btc"},"doc_url":"https://docs.kotova.io/x/api/errors#amount_below_min"}}},"amount_above_max":{"value":{"error":{"code":"amount_above_max","message":"The amount is above the maximum of every available source.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"min_from_amount":"0.00029412","max_from_amount":"0.73529411","currency":"BTC","network":"btc"},"doc_url":"https://docs.kotova.io/x/api/errors#amount_above_max"}}},"pair_unavailable":{"value":{"error":{"code":"pair_unavailable","message":"No source offers this pair right now.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"from":{"currency":"BTC","network":"btc"},"to":{"currency":"XRP","network":"xrp"}},"doc_url":"https://docs.kotova.io/x/api/errors#pair_unavailable"}}},"no_source_available":{"value":{"error":{"code":"no_source_available","message":"No source is available for this request.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reasons":[{"reason":"freeze_protection","sources":["sideshift","changenow","ffio"]},{"reason":"rate_type_unsupported","sources":["chainflip"]}]},"doc_url":"https://docs.kotova.io/x/api/errors#no_source_available"}}},"unknown_currency":{"value":{"error":{"code":"unknown_currency","message":"FOO on network btc is not in the catalog.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"side":"from","currency":"FOO","network":"btc"},"doc_url":"https://docs.kotova.io/x/api/errors#unknown_currency"}}},"currency_unavailable":{"value":{"error":{"code":"currency_unavailable","message":"BTC on network lightning cannot be received right now.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"side":"to","currency":"BTC","network":"lightning"},"doc_url":"https://docs.kotova.io/x/api/errors#currency_unavailable"}}},"same_currency":{"value":{"error":{"code":"same_currency","message":"The currency and network to send and to receive are the same.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"currency":"BTC","network":"btc"},"doc_url":"https://docs.kotova.io/x/api/errors#same_currency"}}}}}}},"429":{"description":"The account budget is spent, or (`details.reason: fanout`) too many quotes this minute had to ask the sources: reuse amounts, or retry after `Retry-After`. A refused call costs nothing.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"account":{"value":{"error":{"code":"rate_limited","message":"Rate limit of 250 units per 60 s reached. Retry in 34 s.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"limit":250,"remaining":0,"reset_seconds":34,"weight":1},"doc_url":"https://docs.kotova.io/x/api/errors#rate_limited"}}},"fanout":{"value":{"error":{"code":"rate_limited","message":"Too many quotes that could not be served from the cache (31 per minute). Retry in 34 s, or reuse amounts.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"fanout","limit":31,"remaining":0,"reset_seconds":34},"doc_url":"https://docs.kotova.io/x/api/errors#rate_limited"}}}}}}},"500":{"$ref":"#/components/responses/InternalError"},"503":{"description":"`sources_unavailable`: no source could be reached (retry after `Retry-After`); `service_unavailable`: the API is unavailable.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"sources_unavailable":{"value":{"error":{"code":"sources_unavailable","message":"No source could be reached right now. Retry shortly.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"retry_after_seconds":10},"doc_url":"https://docs.kotova.io/x/api/errors#sources_unavailable"}}},"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Retry shortly.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"storage_unavailable"},"doc_url":"https://docs.kotova.io/x/api/errors#service_unavailable"}}}}}}}}}},"/orders":{"post":{"operationId":"createOrder","tags":["Orders"],"summary":"Create an order from a quote","x-kotova-weight":50,"description":"Creates the order at the source of the quote — or, when that source cannot take it, at the next best source of the quote (see below) — and answers 201 with the order: show the end user `deposit.address`, `deposit.amount` and (when set) `deposit.memo`, and track it with GET /orders/{id}.\n\n**Refund address.** Recommended (required only when the quote says `requirements.refund_address: required`). It goes to the source with the order wherever the source takes it then — the source's `refund_address_forwarding` is `at_creation` (ChangeNOW, Changelly, StealthEX, Exolix, Godex, SideShift, Chainflip) — so a refund needs no extra step, and more fallback sources stay eligible; that source checks it, and a refusal is a 422 `invalid_address` with nothing created. FF.io (`when_needed`) and CCE.CASH (`none`) take none at creation: the address is kept with the order, `refund.forwarded` is false and the 201 carries the warning `refund_address_on_file`.\n\nPaste the `quote_id` from POST /quote into the body (the example's id is a placeholder: it is the createQuote example's, and a real call answers 404 `quote_not_found` for it). Weight 50; a replay or an error answered before the source was contacted costs 1. Send an `Idempotency-Key` so a retry after a timeout can never create a second order. The answer can take up to 90 s when fallback sources are tried; use a client timeout of at least 100 s and the same Idempotency-Key on a retry (409 `idempotency_in_progress` while the first request is still running: repeat after `Retry-After`).\n\n**Next best source.** By default (`retry_next_best_source` true) the order does not fail when the quote's source cannot take it — it is unavailable, refuses the order, or cannot create it right now: the order is placed with the first of the quote's `fallback_sources` that can, in their order, and only that order is answered. Its `source` names the source that created it (show that notice from now on), its amounts are that source's, and `warnings` has `source_fallback` {`quoted_source`, `reason`} (again on an Idempotency-Key replay; GET /orders/{id} does not carry it). Because of this, show the notices of the quote's `fallback_sources` before the end user confirms, or send `retry_next_best_source: false` to use the quote's source only. An address or memo a source rejects (422 `invalid_address`, `details.field` `to_address`, `to_memo`, `refund_address` or `refund_memo` — also when the source only says so in its message: it names the field, or says the address or memo is invalid, missing or similar) and an unknown outcome are never retried at another source. The request costs 50 once, however many sources are tried.\n\nA failed create — no source took the order: 502 `source_error` with `details.retryable` (true: nothing was created — re-quote and retry; false with `reason: outcome_unknown`: the source may hold the order, so the quote and the Idempotency-Key stay used — contact api@kotova.io with the request id). 503 `source_unavailable`: no source could take an order right now (not available, or the last one asked was rate limited) — re-quote. With `retry_next_best_source`, `details.sources_tried` lists every source tried and why it did not take the order — also on a 422 `invalid_address` or a 500 from one of the quote's `fallback_sources`.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderRequest"},"example":{"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","to_address":"TXk8rQ7cKz3qWv5m2NbP9yLh4Gd6Sa1EjF","refund_address":"REPLACE_WITH_YOUR_BTC_REFUND_ADDRESS","partner_order_id":"shop-order-1042","lang":"en","retry_next_best_source":true}}}},"responses":{"201":{"description":"The order was created (or, with `Idempotent-Replayed: true`, an earlier one is answered again: as it is now, with its `source_fallback` warning when a fallback source created it and its `refund_address_on_file` warning when its refund address is on file only).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Location":{"$ref":"#/components/headers/Location"},"Idempotent-Replayed":{"$ref":"#/components/headers/Idempotent-Replayed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"example":{"id":"X-7KQ2ZD","status":"waiting_for_deposit","is_final":false,"status_detail":null,"rate_type":"variable","created_at":"2026-11-10T10:15:39Z","updated_at":"2026-11-10T10:15:39Z","expires_at":"2026-11-10T11:15:39Z","completed_at":null,"from":{"currency":"BTC","network":"btc","amount":"0.05","amount_received":null},"to":{"currency":"USDT","network":"trx","amount":"3389.8","amount_sent":null,"address":"TXk8rQ7cKz3qWv5m2NbP9yLh4Gd6Sa1EjF","memo":null},"deposit":{"address":"bc1q9h7garjv2gx0s4kd3mzt6v8wcl5ul3xzq0p2ne","memo":null,"memo_label":null,"amount":"0.05"},"refund":{"address":"REPLACE_WITH_YOUR_BTC_REFUND_ADDRESS","memo":null,"forwarded":true},"transactions":{"deposit":null,"payout":null,"refund":null},"order_url":"https://app.kotova.io/x/X-7KQ2ZD","estimated_duration_seconds":1500,"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","partner_order_id":"shop-order-1042","provider":{"name":"Kotova X","icon":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon.svg","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon.svg"},"icon_png":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon-256.png","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon-256.png"},"website_url":"https://app.kotova.io"},"source":{"slug":"sideshift","name":"SideShift","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_sideshift.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_sideshift.svg"},"terms_url":"https://sideshift.ai/legal","notice":{"text":"The exchange service is provided by SideShift. Creating an order confirms your agreement with the SideShift rules.","link_text":"SideShift rules","link_url":"https://sideshift.ai/legal","lang":"en"},"order_id":"7f3c1e9a2b5d4c8e","tracking_url":"https://sideshift.ai/orders/7f3c1e9a2b5d4c8e"},"warnings":[]}}}},"400":{"description":"Malformed request.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_allowed_with_quote_id":{"value":{"error":{"code":"invalid_request","message":"amount is fixed by the quote; send quote_id with the recipient fields only.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"amount","reason":"not_allowed_with_quote_id"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"quote_id_format":{"value":{"error":{"code":"invalid_request","message":"A quote_id looks like q_ followed by 22 letters and digits.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"quote_id","reason":"invalid_format"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"idempotency_key":{"value":{"error":{"code":"invalid_request","message":"Idempotency-Key must be 8-64 characters of A-Z a-z 0-9 _ - : .","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"Idempotency-Key","reason":"invalid_format"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/AffiliateInactive"},"404":{"description":"No such quote for your account (unknown, gone, or another account's).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"quote_not_found","message":"No quote with this id exists for your account.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP"},"doc_url":"https://docs.kotova.io/x/api/errors#quote_not_found"}}}}},"409":{"description":"The quote was already used (`details.order_id`; null while a request with this quote is still running at a source or its outcome is unknown — do not re-quote and place it again), or the Idempotency-Key conflicts or is still in progress (`idempotency_in_progress`: the first request with the key is still running — repeat after `Retry-After`; up to about 100 s after it arrived once it has contacted a source).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"quote_already_used":{"value":{"error":{"code":"quote_already_used","message":"This quote has already been used to create an order.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","order_id":"X-7KQ2ZD"},"doc_url":"https://docs.kotova.io/x/api/errors#quote_already_used"}}},"idempotency_conflict":{"value":{"error":{"code":"idempotency_conflict","message":"This Idempotency-Key was already used with a different request body.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"header":"Idempotency-Key"},"doc_url":"https://docs.kotova.io/x/api/errors#idempotency_conflict"}}},"idempotency_in_progress":{"value":{"error":{"code":"idempotency_in_progress","message":"A request with this Idempotency-Key is still being processed.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","doc_url":"https://docs.kotova.io/x/api/errors#idempotency_in_progress"}}}}}}},"410":{"description":"The quote expired: request a new one.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"quote_expired","message":"This quote has expired. Request a new quote.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","expires_at":"2026-11-10T10:17:03Z"},"doc_url":"https://docs.kotova.io/x/api/errors#quote_expired"}}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"description":"An address or memo does not fit, or the quote's source needs a refund address. A source's refusal is `invalid_address` with `reason: rejected_by_source` and `field` `to_address`, `to_memo`, `refund_address` or `refund_memo` (+ `fields` when the source did not say which; + `sources_tried` when it was one of the quote's `fallback_sources`) — whether or not `retry_next_best_source` is on.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_address":{"value":{"error":{"code":"invalid_address","message":"to_address is not a valid address on network trx.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"to_address","reason":"format","network":"trx"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_address"}}},"rejected_by_source":{"value":{"error":{"code":"invalid_address","message":"The source rejected to_address.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"to_address","reason":"rejected_by_source","source":"sideshift"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_address"}}},"refund_memo_rejected_by_source":{"value":{"error":{"code":"invalid_address","message":"The source rejected refund_memo.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"refund_memo","reason":"rejected_by_source","source":"changenow"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_address"}}},"memo_not_supported":{"value":{"error":{"code":"memo_not_supported","message":"Network trx does not support a memo; remove to_memo.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"to_memo","network":"trx"},"doc_url":"https://docs.kotova.io/x/api/errors#memo_not_supported"}}},"refund_address_required":{"value":{"error":{"code":"refund_address_required","message":"The source of this quote needs a refund address on btc (where the deposit comes from).","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"refund_address","network":"btc","source":"chainflip"},"doc_url":"https://docs.kotova.io/x/api/errors#refund_address_required"}}}}}}},"429":{"description":"`rate_limited`: the account budget is spent. `order_cap_reached`: too many open unfunded orders, or too many orders in 24 hours.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"value":{"error":{"code":"rate_limited","message":"Rate limit of 250 units per 60 s reached. Retry in 34 s.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"limit":250,"remaining":0,"reset_seconds":34,"weight":50},"doc_url":"https://docs.kotova.io/x/api/errors#rate_limited"}}},"order_cap_reached":{"value":{"error":{"code":"order_cap_reached","message":"Your account has 20 orders still waiting for a deposit (limit 20). Retry once some are funded or expire.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"cap":"open_unfunded","limit":20,"current":20},"doc_url":"https://docs.kotova.io/x/api/errors#order_cap_reached"}}}}}}},"500":{"description":"Unexpected error. With `details.order_id` the order exists: read it with GET /orders/{id}. With `details.sources_tried` (`retry_next_best_source`), the create at one of the quote's `fallback_sources` failed on our side and nothing was created.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"internal_error","message":"The order X-7KQ2ZD was created but could not be read back. Read it with GET /x/v1/orders/X-7KQ2ZD.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"order_id":"X-7KQ2ZD"},"doc_url":"https://docs.kotova.io/x/api/errors#internal_error"}}}}},"502":{"description":"No source created the order (`details.retryable`; `details.sources_tried` with `retry_next_best_source`). `reason: idempotency_outcome_unknown`: an earlier request with this Idempotency-Key reached a source and its outcome is unknown — it answered `outcome_unknown`, or it never finished — so the key stays blocked for 24 hours.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"transient":{"value":{"error":{"code":"source_error","message":"The source could not create the order right now; nothing was created. Request a new quote and retry.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"source":"changenow","retryable":true,"sources_tried":[{"source":"sideshift","reason":"unavailable"},{"source":"changenow","reason":"unavailable"}]},"doc_url":"https://docs.kotova.io/x/api/errors#source_error"}}},"outcome_unknown":{"value":{"error":{"code":"source_error","message":"The source did not confirm the order, and it may exist there. To avoid a duplicate, this quote and Idempotency-Key stay used; contact api@kotova.io with the request id before retrying.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"source":"sideshift","retryable":false,"reason":"outcome_unknown","sources_tried":[{"source":"sideshift","reason":"outcome_unknown"}]},"doc_url":"https://docs.kotova.io/x/api/errors#source_error"}}},"idempotency_key_blocked":{"value":{"error":{"code":"source_error","message":"An earlier request with this Idempotency-Key reached the source, and its outcome is unknown. To avoid a duplicate order this key stays blocked for 24 hours; contact api@kotova.io with the request id.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"retryable":false,"reason":"idempotency_outcome_unknown"},"doc_url":"https://docs.kotova.io/x/api/errors#source_error"}}}}}}},"503":{"description":"`source_unavailable`: neither the quote's source nor (with `retry_next_best_source`) its fallback sources can take an order right now — request a new quote. `service_unavailable`: the API is unavailable.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"source_unavailable":{"value":{"error":{"code":"source_unavailable","message":"The source of this quote is temporarily unavailable. Request a new quote.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"source":"sideshift","reason":"busy","requote":true,"sources_tried":[{"source":"sideshift","reason":"busy"},{"source":"changenow","reason":"busy"}]},"doc_url":"https://docs.kotova.io/x/api/errors#source_unavailable"}}},"service_unavailable":{"value":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Retry shortly.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"storage_unavailable"},"doc_url":"https://docs.kotova.io/x/api/errors#service_unavailable"}}}}}}}}},"get":{"operationId":"listOrders","tags":["Orders"],"summary":"List your orders","x-kotova-weight":1,"description":"Your account's API orders (from any of its keys, current or revoked), newest first, as summaries. Never refreshes from the sources: use GET /orders/{id} to track one order.","parameters":[{"name":"status","in":"query","required":false,"description":"Comma-separated order statuses: waiting_for_deposit, confirming_deposit, exchanging, sending, completed, action_required, refunding, refunded, expired.","schema":{"type":"string"},"example":"waiting_for_deposit,confirming_deposit"},{"name":"partner_order_id","in":"query","required":false,"description":"Only orders with this partner_order_id.","schema":{"$ref":"#/components/schemas/PartnerOrderId"},"example":"shop-order-1042"},{"name":"created_after","in":"query","required":false,"description":"Created at or after (ISO-8601 with a zone).","schema":{"type":"string","format":"date-time"},"example":"2026-11-01T00:00:00Z"},{"name":"created_before","in":"query","required":false,"description":"Created before (exclusive).","schema":{"type":"string","format":"date-time"},"example":"2026-11-11T00:00:00Z"},{"name":"limit","in":"query","required":false,"description":"Page size, 1-100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"example":20},{"name":"cursor","in":"query","required":false,"description":"`next_cursor` of the previous page.","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"A page of orders.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderList"},"example":{"data":[{"id":"X-7KQ2ZD","status":"completed","is_final":true,"rate_type":"variable","created_at":"2026-11-10T10:15:39Z","updated_at":"2026-11-10T10:41:12Z","from":{"currency":"BTC","network":"btc","amount":"0.05"},"to":{"currency":"USDT","network":"trx","amount":"3389.8"},"source":{"slug":"sideshift"},"partner_order_id":"shop-order-1042","order_url":"https://app.kotova.io/x/X-7KQ2ZD"}],"has_more":true,"next_cursor":"eyJjIjoiMjAyNi0xMS0xMFQxMDoxNTozOS4xMjM0NTZaIiwiaSI6IlgtN0tRMlpEIn0"}}}},"400":{"description":"Invalid parameter.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid_value":{"value":{"error":{"code":"invalid_request","message":"Unknown order status \"done\".","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"status","reason":"invalid_value","allowed":["waiting_for_deposit","confirming_deposit","exchanging","sending","completed","action_required","refunding","refunded","expired"]},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"cursor":{"value":{"error":{"code":"invalid_request","message":"cursor must be a next_cursor value from this endpoint.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"cursor","reason":"invalid_value"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/AffiliateInactive"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/orders/{id}":{"get":{"operationId":"getOrder","tags":["Orders"],"summary":"Get an order","x-kotova-weight":1,"description":"One order of your account (created with any of its keys, current or revoked). The read may first refresh the order from its source — at most once per order per 10 s while it is in progress and once per 60 s while it is only followed up (refunding, expired inside the late-deposit window, done without a payout hash), never waiting more than about 6 s — and says so in `X-Kotova-Status-Refreshed`. Poll every 15-30 s until `is_final`.","parameters":[{"$ref":"#/components/parameters/OrderIdPath"},{"$ref":"#/components/parameters/Lang"}],"responses":{"200":{"description":"The order.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Kotova-Status-Refreshed":{"$ref":"#/components/headers/X-Kotova-Status-Refreshed"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"examples":{"completed":{"summary":"Completed","value":{"id":"X-7KQ2ZD","status":"completed","is_final":true,"status_detail":null,"rate_type":"variable","created_at":"2026-11-10T10:15:39Z","updated_at":"2026-11-10T10:41:12Z","expires_at":"2026-11-10T11:15:39Z","completed_at":"2026-11-10T10:41:12Z","from":{"currency":"BTC","network":"btc","amount":"0.05","amount_received":"0.05"},"to":{"currency":"USDT","network":"trx","amount":"3389.8","amount_sent":"3390.15","address":"TXk8rQ7cKz3qWv5m2NbP9yLh4Gd6Sa1EjF","memo":null},"deposit":{"address":"bc1q9h7garjv2gx0s4kd3mzt6v8wcl5ul3xzq0p2ne","memo":null,"memo_label":null,"amount":"0.05"},"refund":{"address":"REPLACE_WITH_YOUR_BTC_REFUND_ADDRESS","memo":null,"forwarded":true},"transactions":{"deposit":{"hash":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b","explorer_url":"https://mempool.space/tx/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b","confirmations":3,"required_confirmations":2},"payout":{"hash":"c3a2d6e9b1f04e5a8d7c6b5a49382716f5e4d3c2b1a09f8e7d6c5b4a39281706","explorer_url":"https://tronscan.org/#/transaction/c3a2d6e9b1f04e5a8d7c6b5a49382716f5e4d3c2b1a09f8e7d6c5b4a39281706","confirmations":null},"refund":null},"order_url":"https://app.kotova.io/x/X-7KQ2ZD","estimated_duration_seconds":1500,"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","partner_order_id":"shop-order-1042","provider":{"name":"Kotova X","icon":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon.svg","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon.svg"},"icon_png":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon-256.png","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon-256.png"},"website_url":"https://app.kotova.io"},"source":{"slug":"sideshift","name":"SideShift","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_sideshift.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_sideshift.svg"},"terms_url":"https://sideshift.ai/legal","notice":{"text":"The exchange service is provided by SideShift. Creating an order confirms your agreement with the SideShift rules.","link_text":"SideShift rules","link_url":"https://sideshift.ai/legal","lang":"en"},"order_id":"7f3c1e9a2b5d4c8e","tracking_url":"https://sideshift.ai/orders/7f3c1e9a2b5d4c8e"},"warnings":[]}},"action_required":{"summary":"Action required: amount mismatch","value":{"id":"X-7KQ2ZD","status":"action_required","is_final":false,"status_detail":{"reason":"amount_mismatch","since":"2026-11-10T10:40:00Z","auto_resolution":"refund","auto_resolution_at":"2026-11-10T11:40:00Z","resolve_url":"https://app.kotova.io/x/X-7KQ2ZD"},"rate_type":"variable","created_at":"2026-11-10T10:15:39Z","updated_at":"2026-11-10T10:40:00Z","expires_at":"2026-11-10T11:15:39Z","completed_at":null,"from":{"currency":"BTC","network":"btc","amount":"0.05","amount_received":"0.0312"},"to":{"currency":"USDT","network":"trx","amount":"3389.8","amount_sent":null,"address":"TXk8rQ7cKz3qWv5m2NbP9yLh4Gd6Sa1EjF","memo":null},"deposit":{"address":"bc1q9h7garjv2gx0s4kd3mzt6v8wcl5ul3xzq0p2ne","memo":null,"memo_label":null,"amount":"0.05"},"refund":{"address":"REPLACE_WITH_YOUR_BTC_REFUND_ADDRESS","memo":null,"forwarded":true},"transactions":{"deposit":{"hash":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b","explorer_url":"https://mempool.space/tx/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b","confirmations":4,"required_confirmations":2},"payout":null,"refund":null},"order_url":"https://app.kotova.io/x/X-7KQ2ZD","estimated_duration_seconds":1500,"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","partner_order_id":"shop-order-1042","provider":{"name":"Kotova X","icon":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon.svg","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon.svg"},"icon_png":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon-256.png","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon-256.png"},"website_url":"https://app.kotova.io"},"source":{"slug":"sideshift","name":"SideShift","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_sideshift.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_sideshift.svg"},"terms_url":"https://sideshift.ai/legal","notice":{"text":"The exchange service is provided by SideShift. Creating an order confirms your agreement with the SideShift rules.","link_text":"SideShift rules","link_url":"https://sideshift.ai/legal","lang":"en"},"order_id":"7f3c1e9a2b5d4c8e","tracking_url":"https://sideshift.ai/orders/7f3c1e9a2b5d4c8e"},"warnings":[]}},"payout_on_hold":{"summary":"Action required: payout on hold","value":{"id":"X-7KQ2ZD","status":"action_required","is_final":false,"status_detail":{"reason":"payout_on_hold","since":"2026-11-10T10:38:20Z","auto_resolution":null,"auto_resolution_at":null,"resolve_url":null},"rate_type":"variable","created_at":"2026-11-10T10:15:39Z","updated_at":"2026-11-10T10:15:39Z","expires_at":"2026-11-10T11:15:39Z","completed_at":null,"from":{"currency":"BTC","network":"btc","amount":"0.05","amount_received":null},"to":{"currency":"USDT","network":"trx","amount":"3389.8","amount_sent":null,"address":"TXk8rQ7cKz3qWv5m2NbP9yLh4Gd6Sa1EjF","memo":null},"deposit":{"address":"bc1q9h7garjv2gx0s4kd3mzt6v8wcl5ul3xzq0p2ne","memo":null,"memo_label":null,"amount":"0.05"},"refund":{"address":"REPLACE_WITH_YOUR_BTC_REFUND_ADDRESS","memo":null,"forwarded":true},"transactions":{"deposit":null,"payout":null,"refund":null},"order_url":"https://app.kotova.io/x/X-7KQ2ZD","estimated_duration_seconds":1500,"quote_id":"q_5mJc2Vq9XkT3nR8bYw1LdP","partner_order_id":"shop-order-1042","provider":{"name":"Kotova X","icon":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon.svg","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon.svg"},"icon_png":{"url":"https://cdn.kotova.io/images/brand/kotova-x/icon-256.png","fallback_url":"https://assets.kotova.io/images/brand/kotova-x/icon-256.png"},"website_url":"https://app.kotova.io"},"source":{"slug":"sideshift","name":"SideShift","kind":"centralized","icon":{"url":"https://cdn.kotova.io/images/counterparties/cp_icon_sideshift.svg","fallback_url":"https://assets.kotova.io/images/counterparties/cp_icon_sideshift.svg"},"terms_url":"https://sideshift.ai/legal","notice":{"text":"The exchange service is provided by SideShift. Creating an order confirms your agreement with the SideShift rules.","link_text":"SideShift rules","link_url":"https://sideshift.ai/legal","lang":"en"},"order_id":"7f3c1e9a2b5d4c8e","tracking_url":"https://sideshift.ai/orders/7f3c1e9a2b5d4c8e"},"warnings":[]}}}}}},"400":{"description":"The id is not an order id.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"An order id looks like X-7KQ2ZD.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"id","reason":"invalid_format"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/AffiliateInactive"},"404":{"description":"No such order for your account.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"order_not_found","message":"No order with this id exists for your account.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"id":"X-7KQ2ZD"},"doc_url":"https://docs.kotova.io/x/api/errors#order_not_found"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/addresses/validate":{"post":{"operationId":"validateAddress","tags":["Utilities"],"summary":"Check an address","x-kotova-weight":1,"description":"Checks an address (and memo) against the network's format rule — the check POST /orders applies. Advisory: `valid: null` means there is no rule for the network, and the source makes the binding check when the order is created. No source is called.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateAddressRequest"},"example":{"currency":"USDT","network":"trx","address":"TXk8rQ7cKz3qWv5m2NbP9yLh4Gd6Sa1EjF"}}}},"responses":{"200":{"description":"The verdict.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddressValidation"},"example":{"valid":true,"checked":"format","currency":"USDT","network":"trx","memo":{"supported":false,"valid":null},"warnings":[]}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/AffiliateInactive"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"description":"The currency is not on that network in the catalog.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unknown_currency","message":"FOO on network trx is not in the catalog.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"currency":"FOO","network":"trx"},"doc_url":"https://docs.kotova.io/x/api/errors#unknown_currency"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/me":{"get":{"operationId":"getMe","tags":["Account"],"summary":"Your key, account and limits","x-kotova-weight":1,"description":"The calling key, its account, the rate limit and today's usage. No parameters.","responses":{"200":{"description":"The key and its account.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"},"example":{"key":{"public_key":"ktv_pk_3f9a7c2kd8q1m4x6b2n5r7t9","created_at":"2026-11-03T09:12:44Z","last_used_at":"2026-11-10T10:12:01Z"},"affiliate":{"ref_code":"KX7M2Q","status":"active"},"rate_limit":{"limit":250,"remaining":243,"window_seconds":60,"resets_at":"2026-11-10T10:16:00Z","weights":{"create_order":50,"default":1}},"usage_today":{"quotes":12,"orders":1,"reads":40,"validations":0,"limited":0},"mock":false}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/AffiliateInactive"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ktv_sk_…","description":"`Authorization: Bearer ktv_sk_…` — the secret of your API key (`ktv_sk_` + 46 letters and digits), shown once when you create the key on your Kotova account page. Never send it from a browser or put it in a URL."}},"schemas":{"Decimal":{"type":"string","pattern":"^(0|[1-9][0-9]*)(\\.[0-9]*[1-9])?$","description":"A decimal amount as a string: no exponent, no sign, no trailing zeros, at most min(network decimals, 12) fractional digits. Amounts the end user sends are rounded up, amounts they receive are rounded down.","examples":["0.05"]},"RequestAmount":{"type":"string","pattern":"^[0-9]+(\\.[0-9]+)?$","description":"An amount greater than zero as a plain decimal string (\"0.05\"): no exponent, no sign, at most 16 integer digits and at most min(network decimals, 12) fractional digits on the side it refers to (400 `too_many_decimals` otherwise; trailing zeros do not count). A JSON number is accepted only when it prints as a plain decimal — send strings.","examples":["0.05"]},"Timestamp":{"type":"string","format":"date-time","description":"ISO-8601 UTC with \"Z\", second precision.","examples":["2026-11-10T10:15:04Z"]},"CurrencyId":{"type":"string","pattern":"^[A-Za-z0-9.]{1,12}$","description":"A currency identifier: the ticker (`BTC`, `USDT`). Matched case-insensitively; answers use upper case. Deprecated spellings (aliases) are accepted with a `deprecated_alias` warning.","examples":["BTC"]},"NetworkId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,24}$","description":"A network identifier: the network code (`btc`, `trx`, `eth`). Matched case-insensitively; answers use lower case.","examples":["btc"]},"SourceSlug":{"type":"string","pattern":"^[a-z0-9-]{1,30}$","description":"A source identifier (`sideshift`, `chainflip`). See GET /sources.","examples":["sideshift"]},"OrderId":{"type":"string","pattern":"^X-[A-Z0-9]{6}$","description":"The public order id: `X-` followed by 6 characters of A-Z and 0-9. Accepted case-insensitively in paths.","examples":["X-7KQ2ZD"]},"QuoteId":{"type":"string","pattern":"^q_[0-9A-Za-z]{22}$","description":"A single-use quote id: `q_` followed by 22 letters and digits (case-sensitive).","examples":["q_5mJc2Vq9XkT3nR8bYw1LdP"]},"PartnerOrderId":{"type":"string","pattern":"^[A-Za-z0-9._:-]{1,64}$","description":"Your own reference for the order: 1-64 characters of A-Z a-z 0-9 . _ : -. Echoed back on the order and filterable in GET /orders. Not unique.","examples":["shop-order-1042"]},"Lang":{"type":"string","enum":["en","de","it","es","fr","ru"],"default":"en","description":"Language of the source notice. A region suffix (`de-AT`) is accepted. Any other value falls back to `en` with an `unsupported_lang` warning instead of an error."},"RateType":{"type":"string","enum":["fixed","variable"],"description":"Closed enum. `fixed`: the source fixes the rate of the order for its deposit window. `variable`: the rate is set when the deposit arrives."},"AmountType":{"type":"string","enum":["from","to"],"description":"Closed enum. Which side `amount` refers to: `from` = the amount sent, `to` = the amount to receive."},"Icon":{"type":"object","required":["url","fallback_url"],"properties":{"url":{"type":"string","description":"The icon on the Kotova CDN (or, for a foreign host, the URL as stored).","format":"uri"},"fallback_url":{"type":["string","null"],"description":"The same path on the mirror; retry an <img> once with it. Null for a foreign host.","format":"uri"}},"description":"An icon. Path segments are already URL-encoded."},"Memo":{"type":"object","required":["supported","label"],"properties":{"supported":{"type":"boolean","description":"The network takes a memo / destination tag."},"label":{"type":["string","null"],"description":"What the network calls it (\"Memo\", \"Destination Tag\"); null when not supported."}}},"AddressFormat":{"type":"string","description":"Extensible enum: `standard`, or `lightning_invoice` on the Lightning network.","examples":["standard"]},"ErrorCode":{"type":"string","enum":["invalid_request","unauthorized","key_revoked","affiliate_inactive","not_found","order_not_found","quote_not_found","method_not_allowed","quote_already_used","idempotency_conflict","idempotency_in_progress","quote_expired","payload_too_large","unsupported_media_type","unknown_currency","currency_unavailable","same_currency","pair_unavailable","no_source_available","amount_below_min","amount_above_max","refund_address_required","invalid_address","memo_not_supported","rate_limited","order_cap_reached","internal_error","source_error","source_unavailable","sources_unavailable","service_unavailable"],"description":"Stable error codes. New codes may be added at any time: fall back on the HTTP status for a code you do not know. Each code is documented at https://docs.kotova.io/x/api/errors#<code>."},"ErrorBody":{"type":"object","required":["code","message","request_id","doc_url"],"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string","description":"For people; may change. Branch on `code`, never on the message."},"request_id":{"type":"string","description":"The request's id (also in X-Request-Id). Quote it to support.","pattern":"^req_[0-9A-Za-z]{24}$"},"details":{"type":"object","additionalProperties":true,"description":"Machine-readable specifics, when the code has any:\n\n- `invalid_request`: `field` (dot path, e.g. `from.currency`, or a header / parameter name) and `reason` — one of `required`, `invalid_type`, `invalid_format`, `invalid_value` (with `allowed`), `unknown_field`, `unknown_parameter`, `duplicate_parameter`, `too_long`, `too_many`, `too_many_decimals` (with `max_fraction_digits`), `too_many_integer_digits`, `not_positive`, `not_public_unicast`, `from_or_to_required`, `not_allowed_with_quote_id`, `requires_refund_address`, `invalid_json`, `invalid_encoding`.\n- `rate_limited`: `limit`, `remaining`, `reset_seconds`, and `weight` (the account budget) — or `reason`: `fanout` (quotes that ask a source live), `ip` (keyless calls per IP) or `auth_failures` (failed authentications per IP).\n- `order_cap_reached`: `cap` (`open_unfunded` | `created_24h`), `limit`, `current`.\n- `unknown_currency`, `currency_unavailable`: `side` (`from` | `to`; absent on /addresses/validate), `currency`, `network`. `same_currency`: `currency`, `network`. `pair_unavailable`: `from`, `to`.\n- `no_source_available`: `reasons` [{`reason`, `sources`}] with `reason` one of `excluded_by_request`, `freeze_protection`, `rate_type_unsupported`, `end_user_ip_required`, `refund_address_required`, `create_budget_exhausted` (extensible).\n- `amount_below_min`, `amount_above_max`: `min_from_amount`, `max_from_amount` (null = no maximum), `currency`, `network` — always in from-units.\n- `sources_unavailable`: `retry_after_seconds`.\n- `quote_not_found`, `quote_expired` (+ `expires_at`), `quote_already_used` (+ `order_id`, null while unknown): `quote_id`.\n- `order_not_found`: `id`.\n- `invalid_address`: `field` (`to_address` | `refund_address`; with `rejected_by_source` also `to_memo` | `refund_memo`), `reason` (`format` | `rejected_by_source`), and `network` or `source`. When the source did not say which field it refused, `field` is the best guess and `fields` lists every candidate (e.g. [`to_address`, `refund_address`]): check them all. `memo_not_supported`: `field`, `network`. `refund_address_required`: `field`, `network`, `source`.\n- `source_error`: `source`, `retryable` (true: nothing was created — re-quote and retry; false: do not retry blindly) and, when the outcome is unknown, `reason`: `outcome_unknown` (the source may hold the order) or `idempotency_outcome_unknown` (an earlier request with this Idempotency-Key had that outcome, or contacted a source and never finished; `source` is absent).\n- `idempotency_conflict`: `header` (`Idempotency-Key`).\n- `source_unavailable`: `source`, `reason` (`disabled` | `paused` | `busy` | `rate_limited`), `requote: true`.\n- POST /orders with `retry_next_best_source` (default): a `source_error` or `source_unavailable` from its create attempts — and an `invalid_address` or `internal_error` from one of the quote's `fallback_sources` — also carries `sources_tried` [{`source`, `reason`}]: every source of the quote the order was tried at, in order (the quote's source first, then its `fallback_sources`). The `idempotency_outcome_unknown` answer (a replay of a blocked Idempotency-Key) does not. `reason`: `disabled`, `paused`, `busy` (not available, not asked); `rejected`, `unavailable`, `rate_limited` (asked, nothing was created); `invalid_address` (asked: it refused the address, which is sent to no other source — the last entry); `internal` (asked: our side failed and nothing was created — the last entry); `outcome_unknown` (asked, the order may exist there — always the last entry); `refund_address_required` (skipped: no `refund_address` sent); `deadline` (skipped: the request had run too long to ask another source, or its create could not have finished in time). The other fields describe the last source asked; when none was asked (503 `source_unavailable`), the quote's source.\n- `service_unavailable`: `reason` — `disabled` (the API is not enabled), `maintenance`, `catalog_missing` or `storage_unavailable` (extensible: new reasons may be added). Retry after the seconds in `Retry-After` when it is sent.\n- `method_not_allowed`: `allowed`. `payload_too_large`: `max_bytes`. `internal_error`: `order_id` when an order was created but could not be read back."},"doc_url":{"type":"string","description":"Documentation of the code.","format":"uri"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/ErrorBody"}},"description":"The body of every non-2xx answer."},"Warning":{"type":"object","required":["code","message"],"additionalProperties":true,"description":"A non-fatal note in a 2xx body. `code` is an extensible enum — tolerate codes you do not know:\n\n- `unknown_source` {`field`, `sources`}: exclude_sources named slugs the API does not know; they were ignored.\n- `deprecated_alias` {`field`, `given`, `canonical`}: an old spelling was used; switch to `canonical`.\n- `unsupported_lang` {`field`, `supported`}: the notice is in English.\n- `end_user_ip_missing` {`sources`}: these sources need `end_user_ip` and were skipped.\n- `sources_temporarily_skipped` {`sources`}: these sources could not be asked right now (e.g. the source is paused, or this account used up its per-account share of that source's quotes for the current minute); a later quote may be better.\n- `source_fallback` {`quoted_source`, `reason`}: POST /orders — the quote's source could not take the order (`reason`: `disabled`, `paused` or `busy` — not available; `rejected`, `unavailable` or `rate_limited` — it was asked and created nothing), so the order was placed with the next of the quote's `fallback_sources`: the order's `source` names it. The 201 and its Idempotency-Key replays only: GET /orders/{id} does not carry it (compare the order's `source.slug` with the quote's).\n- `refund_address_on_file` {`source`, `intake`}: POST /orders — the order's source does not take a refund address when the order is created, so `refund_address` is kept with the order (`refund.forwarded: false`): `intake` `when_needed` — it is given to the source only if the order needs a refund (FF.io); `none` — support reference only, the source handles refunds itself (CCE.CASH). The 201 and its Idempotency-Key replays only.","properties":{"code":{"type":"string","description":"Extensible enum (see above).","examples":["end_user_ip_missing"]},"message":{"type":"string","description":"For people; may change."}}},"Warnings":{"type":"array","items":{"$ref":"#/components/schemas/Warning"},"description":"Non-fatal notes; usually empty."},"Provider":{"type":"object","required":["name","icon","icon_png","website_url"],"properties":{"name":{"type":"string","description":"Always \"Kotova X\".","examples":["Kotova X"]},"icon":{"$ref":"#/components/schemas/Icon"},"icon_png":{"$ref":"#/components/schemas/Icon"},"website_url":{"type":"string","description":"The Kotova X app, https://app.kotova.io. You may link the Kotova X name or icon to it.","format":"uri"}},"description":"Kotova X, the provider of the service. Show it wherever you offer Kotova X quotes (https://docs.kotova.io/x/api/display-requirements). The parties that execute swaps are sources, never the provider."},"SourceKind":{"type":"string","description":"Extensible enum: `centralized`, `decentralized` or `internal`.","examples":["centralized"]},"SourceNotice":{"type":"object","required":["text","link_text","link_url","lang"],"properties":{"text":{"type":"string","description":"The full notice line, word for word as app.kotova.io shows it before an order is created."},"link_text":{"type":"string","description":"The part of `text` to render as a link."},"link_url":{"type":"string","description":"Where the link goes: the source's rules, or Kotova's Terms of Service for a source without its own.","format":"uri"},"lang":{"$ref":"#/components/schemas/Lang"}},"description":"The notice the end user must see before an order is created (https://docs.kotova.io/x/api/display-requirements)."},"RefundAddressForwarding":{"type":"string","enum":["at_creation","when_needed","none"],"description":"What an order's `refund_address` (and `refund_memo`) is used for at this source — extensible enum:\n\n- `at_creation`: it goes to the source with the order, and the source checks it then (a refusal is 422 `invalid_address` with `field` `refund_address` or `refund_memo`, and nothing is created).\n- `when_needed`: the source takes no refund address when the order is created; it is kept with the order and given to the source only if the order needs a refund (FF.io). A refusal then shows as `status_detail.reason: refund_address_rejected`.\n- `none`: the source never takes one (it handles refunds itself); it is kept with the order for support only (CCE.CASH).\n\nAn order sent with a refund address to a `when_needed` or `none` source carries the warning `refund_address_on_file` and `refund.forwarded: false`."},"Source":{"type":"object","required":["slug","name","kind","icon","terms_url","notice"],"properties":{"slug":{"$ref":"#/components/schemas/SourceSlug"},"name":{"type":"string","description":"Display name.","examples":["SideShift"]},"kind":{"$ref":"#/components/schemas/SourceKind"},"icon":{"description":"Null when the source's logo may not be shown.","oneOf":[{"$ref":"#/components/schemas/Icon"},{"type":"null"}]},"terms_url":{"type":["string","null"],"description":"The source's own rules page; null when the notice links to Kotova's Terms instead.","format":"uri"},"notice":{"$ref":"#/components/schemas/SourceNotice"}},"description":"The source that executes the swap (attribution block)."},"QuoteSource":{"description":"A source block of a quote: the attribution block plus what an order's refund address is used for at this source.","allOf":[{"$ref":"#/components/schemas/Source"},{"type":"object","required":["refund_address_forwarding"],"properties":{"refund_address_forwarding":{"$ref":"#/components/schemas/RefundAddressForwarding"}}}]},"OrderSource":{"description":"The order's source: the attribution block plus the source's own references.","allOf":[{"$ref":"#/components/schemas/Source"},{"type":"object","required":["order_id","tracking_url"],"properties":{"order_id":{"type":["string","null"],"description":"The source's own order id, for support with the source."},"tracking_url":{"type":["string","null"],"description":"The source's tracking page for the order; null when it has none we can link to.","format":"uri"}}}]},"LegInput":{"type":"object","required":["currency","network"],"properties":{"currency":{"$ref":"#/components/schemas/CurrencyId"},"network":{"$ref":"#/components/schemas/NetworkId"}},"additionalProperties":false,"description":"One currency on one network. Exactly these two fields."},"LegRef":{"type":"object","required":["currency","network"],"properties":{"currency":{"type":"string","description":"Ticker, upper case.","examples":["BTC"]},"network":{"type":"string","description":"Network code, lower case.","examples":["btc"]}}},"AmountLeg":{"allOf":[{"$ref":"#/components/schemas/LegRef"},{"type":"object","required":["amount"],"properties":{"amount":{"$ref":"#/components/schemas/Decimal"}}}]},"CurrencyNetwork":{"type":"object","required":["network","network_name","name","ticker","contract_address","token_standard","decimals","memo","address_format","icon","send","receive","send_sources","receive_sources"],"properties":{"network":{"type":"string","description":"Network code.","examples":["trx"]},"network_name":{"type":"string","description":"Network display name.","examples":["TRON"]},"name":{"type":"string","description":"Display name of the currency on this network.","examples":["Tether (TRC20)"]},"ticker":{"type":"string","description":"Display ticker on this network (e.g. BTCB on BSC). Identifiers always use `currency`."},"contract_address":{"type":["string","null"],"description":"Token contract; null for a native coin."},"token_standard":{"type":["string","null"],"description":"TRC20, ERC20, …"},"decimals":{"type":"integer","minimum":0,"description":"On-chain decimals of this leg."},"memo":{"$ref":"#/components/schemas/Memo"},"address_format":{"$ref":"#/components/schemas/AddressFormat"},"icon":{"oneOf":[{"$ref":"#/components/schemas/Icon"},{"type":"null"}]},"send":{"type":"boolean","description":"Usable as `from` through the API right now."},"receive":{"type":"boolean","description":"Usable as `to` through the API right now (never on Lightning in v1)."},"send_sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceSlug"},"description":"Sources that accept this leg as `from` — apply your own exclusions client-side."},"receive_sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceSlug"},"description":"Sources that pay out this leg."}}},"Currency":{"type":"object","required":["currency","name","type","icon","aliases","networks"],"properties":{"currency":{"type":"string","description":"Ticker, upper case.","examples":["USDT"]},"name":{"type":"string","description":"","examples":["Tether"]},"type":{"type":"string","description":"Extensible enum: cryptocurrency, stablecoin, utility_token, meme, …","examples":["stablecoin"]},"icon":{"oneOf":[{"$ref":"#/components/schemas/Icon"},{"type":"null"}]},"aliases":{"type":"array","items":{"type":"string"},"description":"Deprecated spellings still accepted for this currency."},"networks":{"type":"array","items":{"$ref":"#/components/schemas/CurrencyNetwork"}}}},"CatalogMeta":{"type":"object","required":["has_more","next_cursor","catalog_version","updated_at"],"properties":{"has_more":{"type":"boolean","description":"Always false: the whole list is one page."},"next_cursor":{"type":"null"},"catalog_version":{"type":"string","description":"Changes whenever the catalog is rebuilt.","examples":["394da0f044c4"]},"updated_at":{"$ref":"#/components/schemas/Timestamp"}}},"CurrencyList":{"allOf":[{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Currency"}}}},{"$ref":"#/components/schemas/CatalogMeta"}]},"Network":{"type":"object","required":["network","name","symbol","family","icon","memo","address_format","evm_chain_id","explorer_tx_url_template"],"properties":{"network":{"type":"string","description":"Network code.","examples":["xrp"]},"name":{"type":"string","description":"","examples":["XRP Ledger"]},"symbol":{"type":"string","description":"Native coin symbol.","examples":["XRP"]},"family":{"type":"string","description":"Extensible enum, lower case: utxo, evm, solana, tron, cosmos, near, other.","examples":["other"]},"icon":{"oneOf":[{"$ref":"#/components/schemas/Icon"},{"type":"null"}]},"memo":{"$ref":"#/components/schemas/Memo"},"address_format":{"$ref":"#/components/schemas/AddressFormat"},"evm_chain_id":{"type":["integer","null"],"description":"EVM chain id; null for other families."},"explorer_tx_url_template":{"type":["string","null"],"description":"Explorer link for a transaction, with `{hash}` in place of the hash."}}},"NetworkList":{"allOf":[{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Network"}}}},{"$ref":"#/components/schemas/CatalogMeta"}]},"SourceInfo":{"type":"object","required":["slug","name","kind","status","icon","terms_url","rate_types","refund_address","refund_address_forwarding","requires_end_user_ip","freeze_protection","display_order","notice"],"properties":{"slug":{"$ref":"#/components/schemas/SourceSlug"},"name":{"type":"string"},"kind":{"$ref":"#/components/schemas/SourceKind"},"status":{"type":"string","enum":["active","unavailable"],"description":"`unavailable`: listed, but the API does not quote or create there right now."},"icon":{"oneOf":[{"$ref":"#/components/schemas/Icon"},{"type":"null"}]},"terms_url":{"type":["string","null"],"description":"","format":"uri"},"rate_types":{"type":"array","items":{"$ref":"#/components/schemas/RateType"}},"refund_address":{"type":"string","enum":["required","fixed_rate_only","optional"],"description":"When the source needs a refund address at creation. Quotes say it per request in `requirements.refund_address`."},"refund_address_forwarding":{"$ref":"#/components/schemas/RefundAddressForwarding"},"requires_end_user_ip":{"type":"boolean","description":"Quotes and orders at this source need `end_user_ip`; without it the source is skipped."},"freeze_protection":{"type":"boolean","description":"The source cannot freeze funds (`freeze_protection: true` in a quote keeps only these)."},"display_order":{"type":"integer","description":"Tie-break rank when two sources quote the same amount (lower first)."},"notice":{"$ref":"#/components/schemas/SourceNotice"}}},"AttributionRequirements":{"type":"object","required":["provider_display_required","source_notice_required_before_order","docs_url"],"properties":{"provider_display_required":{"type":"boolean"},"source_notice_required_before_order":{"type":"boolean"},"docs_url":{"type":"string","description":"","format":"uri"}}},"SourceList":{"allOf":[{"type":"object","required":["provider","attribution","data","warnings"],"properties":{"provider":{"$ref":"#/components/schemas/Provider"},"attribution":{"$ref":"#/components/schemas/AttributionRequirements"},"data":{"type":"array","items":{"$ref":"#/components/schemas/SourceInfo"}},"warnings":{"$ref":"#/components/schemas/Warnings"}}},{"$ref":"#/components/schemas/CatalogMeta"}]},"Pair":{"type":"object","required":["from","to","rate_types","sources"],"properties":{"from":{"$ref":"#/components/schemas/LegRef"},"to":{"$ref":"#/components/schemas/LegRef"},"rate_types":{"type":"array","items":{"$ref":"#/components/schemas/RateType"},"description":"Rate types at least one serving source offers."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceSlug"},"description":"The sources that serve this pair."}}},"PairList":{"allOf":[{"type":"object","required":["data","warnings"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Pair"}},"warnings":{"$ref":"#/components/schemas/Warnings"}}},{"$ref":"#/components/schemas/CatalogMeta"}]},"Index":{"type":"object","required":["name","version","docs_url","openapi_url","changelog_url","health_url"],"properties":{"name":{"type":"string"},"version":{"type":"string","description":"","examples":["v1"]},"docs_url":{"type":"string","description":"","format":"uri"},"openapi_url":{"type":"string","description":"","format":"uri"},"changelog_url":{"type":"string","description":"","format":"uri"},"health_url":{"type":"string","description":"","format":"uri"}}},"Health":{"type":"object","required":["status","api_version","time","catalog_version","mock"],"properties":{"status":{"type":"string","enum":["ok","degraded"],"description":"`degraded`: the catalog is older than 26 hours (quotes still work; new currencies may be missing)."},"api_version":{"type":"string","description":"","examples":["v1"]},"time":{"$ref":"#/components/schemas/Timestamp"},"catalog_version":{"type":"string"},"mock":{"type":"boolean","description":"Always false on api.kotova.io."}}},"QuoteRequest":{"type":"object","additionalProperties":false,"required":["from","to","amount","rate_type"],"properties":{"from":{"$ref":"#/components/schemas/LegInput","description":"What the end user sends."},"to":{"$ref":"#/components/schemas/LegInput","description":"What the end user receives."},"amount":{"$ref":"#/components/schemas/RequestAmount"},"amount_type":{"$ref":"#/components/schemas/AmountType","default":"from"},"rate_type":{"$ref":"#/components/schemas/RateType","description":"Required: there is no default."},"exclude_sources":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/SourceSlug"},"description":"Sources not to use (at most 20; case-insensitive). Unknown slugs are ignored with an `unknown_source` warning."},"freeze_protection":{"type":"boolean","default":false,"description":"Only sources that cannot freeze funds (GET /sources `freeze_protection`)."},"can_provide_refund_address":{"type":"boolean","default":true,"description":"false: skip sources that need a refund address at creation."},"end_user_ip":{"type":"string","description":"The end user's public IPv4 or IPv6 address (never your server's). Private, CGNAT, loopback, documentation and other special ranges are refused (400 `not_public_unicast`). Without it, sources that need it are skipped and a `end_user_ip_missing` warning is added.","examples":["93.184.216.34"]},"lang":{"$ref":"#/components/schemas/Lang"}}},"Quote":{"type":"object","required":["quote_id","created_at","expires_at","rate_type","amount_type","from","to","rate","limits","estimated_duration_seconds","requirements","filters","provider","source","fallback_sources","warnings"],"properties":{"quote_id":{"$ref":"#/components/schemas/QuoteId","description":"Single use: send it to POST /orders before `expires_at`."},"created_at":{"$ref":"#/components/schemas/Timestamp"},"expires_at":{"$ref":"#/components/schemas/Timestamp","description":"60 s (fixed) or 120 s (variable) after the source answered."},"rate_type":{"$ref":"#/components/schemas/RateType"},"amount_type":{"$ref":"#/components/schemas/AmountType"},"from":{"$ref":"#/components/schemas/AmountLeg"},"to":{"$ref":"#/components/schemas/AmountLeg"},"rate":{"type":"string","description":"to.amount / from.amount, 12 significant digits, truncated.","examples":["67796"]},"limits":{"type":"object","required":["min_from_amount","max_from_amount"],"properties":{"min_from_amount":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}]},"max_from_amount":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}],"description":"Null: no upper limit."}},"description":"The quoted source's bounds, in from-units."},"estimated_duration_seconds":{"type":["integer","null"],"description":"Typical time from deposit to payout."},"requirements":{"type":"object","required":["refund_address","to_memo","refund_memo"],"properties":{"refund_address":{"type":"string","enum":["required","optional"],"description":"`required`: POST /orders must send `refund_address` (on the from network)."},"to_memo":{"type":"string","enum":["optional","not_supported"]},"refund_memo":{"type":"string","enum":["optional","not_supported"]}}},"filters":{"type":"object","required":["exclude_sources","freeze_protection","can_provide_refund_address","end_user_ip_provided"],"properties":{"exclude_sources":{"type":"array","items":{"$ref":"#/components/schemas/SourceSlug"}},"freeze_protection":{"type":"boolean"},"can_provide_refund_address":{"type":"boolean"},"end_user_ip_provided":{"type":"boolean"}},"description":"The request filters as applied."},"provider":{"$ref":"#/components/schemas/Provider"},"source":{"$ref":"#/components/schemas/QuoteSource","description":"The quote's source: every other top-level field describes it. The order is placed with it — or, with `retry_next_best_source` (default) when it cannot take the order, with the first of `fallback_sources` that can. Show its notice before the order."},"fallback_sources":{"type":"array","maxItems":2,"items":{"$ref":"#/components/schemas/FallbackSource"},"description":"The next best sources after `source` (up to 2, best first; [] when there are none). With `retry_next_best_source` (default), POST /orders tries them in this order when `source` cannot take the order: show their notices before the order too, or send `retry_next_best_source: false`."},"warnings":{"$ref":"#/components/schemas/Warnings"}}},"FallbackSource":{"type":"object","required":["source","from","to","requirements"],"properties":{"source":{"$ref":"#/components/schemas/QuoteSource","description":"The fallback source, with the notice to show before the order."},"from":{"type":"object","required":["amount"],"properties":{"amount":{"$ref":"#/components/schemas/Decimal"}},"description":"What the end user sends if this source takes the order (rounded up), in the quote's from currency."},"to":{"type":"object","required":["amount"],"properties":{"amount":{"$ref":"#/components/schemas/Decimal"}},"description":"What the end user receives if this source takes the order (rounded down), in the quote's to currency."},"requirements":{"type":"object","required":["refund_address"],"properties":{"refund_address":{"type":"string","enum":["required","optional"],"description":"`required`: this source is tried only when the order sends `refund_address`; without one it is skipped."}}}},"description":"A source POST /orders places the order with when the quote's own source cannot take it (`retry_next_best_source`, default true), tried in the order of `fallback_sources`. Its own amounts apply then: the order shows them."},"OrderRequest":{"type":"object","additionalProperties":false,"required":["quote_id","to_address"],"properties":{"quote_id":{"type":"string","pattern":"^q_[0-9A-Za-z]{22}$","description":"The `quote_id` of a quote from POST /quote (single use, before its `expires_at`). Pair, amount, rate type and source filters come from the quote: sending any of them here is a 400 `not_allowed_with_quote_id`.","examples":["q_5mJc2Vq9XkT3nR8bYw1LdP"]},"to_address":{"type":"string","minLength":1,"maxLength":4096,"description":"Where the end user receives `to`. Checked against the to network's address format (422 `invalid_address`); the source makes the binding check."},"to_memo":{"type":["string","null"],"maxLength":255,"description":"Memo / destination tag of the recipient. Only on networks with memos (422 `memo_not_supported`)."},"refund_address":{"type":["string","null"],"maxLength":4096,"description":"Where a refund goes, on the FROM network. Recommended; required when the quote says `requirements.refund_address: required` (422 `refund_address_required`). Sent to the source with the order where the source takes it then (`refund_address_forwarding: at_creation`; the source checks it — a refusal is 422 `invalid_address`, field `refund_address`); otherwise kept with the order (`refund.forwarded: false`, warning `refund_address_on_file`)."},"refund_memo":{"type":["string","null"],"maxLength":255,"description":"Memo of the refund address (needs `refund_address`; send it when the refund address is on an exchange account or another address that needs one). Travels with `refund_address`; a source's refusal is 422 `invalid_address`, field `refund_memo`."},"partner_order_id":{"oneOf":[{"$ref":"#/components/schemas/PartnerOrderId"},{"type":"null"}]},"lang":{"$ref":"#/components/schemas/Lang"},"retry_next_best_source":{"type":"boolean","default":true,"description":"`true` (default): when the quote's `source` cannot take the order — it is unavailable, refuses the order, or cannot create it right now — the order is placed with the first of the quote's `fallback_sources` that can, in order, and only that order is returned: its `source` names the source that created it, and `warnings` has `source_fallback`. A fallback source that needs a refund address is skipped when `refund_address` is not sent. An address or memo the source rejects (422 `invalid_address`, with either value of this field) or an unknown outcome (502 `source_error` `outcome_unknown`) is never retried elsewhere. Show the notices of the quote's `fallback_sources` before the end user confirms, or send `false`: only the quote's source is tried. Omit it for the default; `null` or any other non-boolean is a 400 `invalid_request` (`invalid_type`).","examples":[true]}}},"OrderStatus":{"type":"string","enum":["waiting_for_deposit","confirming_deposit","exchanging","sending","completed","action_required","refunding","refunded","expired"],"description":"CLOSED enum — a new value would only come with /x/v2:\n\n- `waiting_for_deposit`: waiting for the end user's deposit.\n- `confirming_deposit`: the deposit was seen and is confirming.\n- `exchanging`: the source is swapping.\n- `sending`: the payout is being sent.\n- `completed`: the payout was sent (final).\n- `action_required`: the source reported a problem or holds the order — see `status_detail`.\n- `refunding`: a refund is under way.\n- `refunded`: the refund was sent (final).\n- `expired`: no deposit within the window. `is_final` turns true once the source's late-deposit window has passed; until then a late deposit can still revive the order."},"StatusDetailReason":{"type":"string","description":"Extensible enum:\n\n- `amount_mismatch`: the deposit differs from the order (or is outside the source's limits).\n- `late_deposit`: the deposit arrived after the order expired.\n- `source_review`: the source holds the order for a review and resolves it itself.\n- `payout_on_hold`: the source reports the swap done but holds the payout. Contact api@kotova.io with the order id.\n- `refund_address_rejected`: the source refused the refund address; the end user enters a new one at `resolve_url`.\n- `other`.","examples":["amount_mismatch"]},"StatusDetail":{"type":"object","required":["reason","since","auto_resolution","auto_resolution_at","resolve_url"],"properties":{"reason":{"$ref":"#/components/schemas/StatusDetailReason"},"since":{"oneOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"auto_resolution":{"type":["string","null"],"enum":["refund","continue",null],"description":"What happens at `auto_resolution_at` if nobody acts first; null: the source resolves it itself."},"auto_resolution_at":{"oneOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"resolve_url":{"type":["string","null"],"description":"The order page, where the end user can choose; null when there is nothing to choose.","format":"uri"}}},"Transaction":{"type":"object","required":["hash","explorer_url","confirmations"],"properties":{"hash":{"type":"string"},"explorer_url":{"type":["string","null"],"description":"","format":"uri"},"confirmations":{"type":["integer","null"],"minimum":0}}},"DepositTransaction":{"allOf":[{"$ref":"#/components/schemas/Transaction"},{"type":"object","required":["required_confirmations"],"properties":{"required_confirmations":{"type":["integer","null"],"minimum":0,"description":"Confirmations the source needs before it treats the deposit as final; null when unknown."}}}]},"Order":{"type":"object","required":["id","status","is_final","status_detail","rate_type","created_at","updated_at","expires_at","completed_at","from","to","deposit","refund","transactions","order_url","estimated_duration_seconds","quote_id","partner_order_id","provider","source","warnings"],"properties":{"id":{"$ref":"#/components/schemas/OrderId"},"status":{"$ref":"#/components/schemas/OrderStatus"},"is_final":{"type":"boolean","description":"Nothing will change any more. Poll until true (every 15-30 s)."},"status_detail":{"description":"Set for `action_required` (and for `refunding` when the reason is known).","oneOf":[{"$ref":"#/components/schemas/StatusDetail"},{"type":"null"}]},"rate_type":{"$ref":"#/components/schemas/RateType"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"expires_at":{"oneOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"The deposit deadline the order page counts down."},"completed_at":{"oneOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"Set only once the status is `completed`."},"from":{"allOf":[{"$ref":"#/components/schemas/LegRef"},{"type":"object","required":["amount","amount_received"],"properties":{"amount":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}],"description":"The order amount: binding for fixed rates, indicative for variable rates."},"amount_received":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}],"description":"The deposit as seen."}}}]},"to":{"allOf":[{"$ref":"#/components/schemas/LegRef"},{"type":"object","required":["amount","amount_sent","address","memo"],"properties":{"amount":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}],"description":"Binding for fixed rates, indicative for variable rates."},"amount_sent":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}],"description":"The payout as sent."},"address":{"type":"string"},"memo":{"type":["string","null"]}}}]},"deposit":{"type":"object","required":["address","memo","memo_label","amount"],"properties":{"address":{"type":["string","null"],"description":"Where the end user sends `deposit.amount`."},"memo":{"type":["string","null"],"description":"When set, the end user MUST send it with the deposit — show it prominently."},"memo_label":{"type":["string","null"],"description":"What to call the memo (\"Memo\", \"Destination Tag\")."},"amount":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}]}},"description":"What the end user sends, and where."},"refund":{"type":"object","required":["address","memo","forwarded"],"properties":{"address":{"type":["string","null"]},"memo":{"type":["string","null"]},"forwarded":{"type":"boolean","description":"true: the refund address went to the source with the order (its `refund_address_forwarding` is `at_creation`). false: there is none, or it is kept with the order only (`when_needed`: given to the source if the order needs a refund; `none`: support reference)."}},"description":"The refund address and memo of the order (null when none was sent, or after the source refused it: `status_detail.reason` `refund_address_rejected`)."},"transactions":{"type":"object","required":["deposit","payout","refund"],"properties":{"deposit":{"oneOf":[{"$ref":"#/components/schemas/DepositTransaction"},{"type":"null"}]},"payout":{"oneOf":[{"$ref":"#/components/schemas/Transaction"},{"type":"null"}]},"refund":{"oneOf":[{"$ref":"#/components/schemas/Transaction"},{"type":"null"}]}}},"order_url":{"type":"string","description":"The order page for the end user; it opens after entering the recipient address. Optional to show: to keep the end user in your app, show the order from GET /orders/{id} and send them to `status_detail.resolve_url` only when the order needs a decision.","format":"uri"},"estimated_duration_seconds":{"type":["integer","null"]},"quote_id":{"oneOf":[{"$ref":"#/components/schemas/QuoteId"},{"type":"null"}]},"partner_order_id":{"oneOf":[{"$ref":"#/components/schemas/PartnerOrderId"},{"type":"null"}]},"provider":{"$ref":"#/components/schemas/Provider"},"source":{"$ref":"#/components/schemas/OrderSource"},"warnings":{"$ref":"#/components/schemas/Warnings"}}},"OrderListItem":{"type":"object","required":["id","status","is_final","rate_type","created_at","updated_at","from","to","source","partner_order_id","order_url"],"properties":{"id":{"$ref":"#/components/schemas/OrderId"},"status":{"$ref":"#/components/schemas/OrderStatus"},"is_final":{"type":"boolean"},"rate_type":{"$ref":"#/components/schemas/RateType"},"created_at":{"$ref":"#/components/schemas/Timestamp"},"updated_at":{"$ref":"#/components/schemas/Timestamp"},"from":{"allOf":[{"$ref":"#/components/schemas/LegRef"},{"type":"object","required":["amount"],"properties":{"amount":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}]}}}]},"to":{"allOf":[{"$ref":"#/components/schemas/LegRef"},{"type":"object","required":["amount"],"properties":{"amount":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}]}}}]},"source":{"type":"object","required":["slug"],"properties":{"slug":{"$ref":"#/components/schemas/SourceSlug"}}},"partner_order_id":{"oneOf":[{"$ref":"#/components/schemas/PartnerOrderId"},{"type":"null"}]},"order_url":{"type":"string","description":"","format":"uri"}},"description":"A summary; GET /orders/{id} has the full order."},"OrderList":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderListItem"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` for the next page; null on the last page."}}},"ValidateAddressRequest":{"type":"object","additionalProperties":false,"required":["currency","network","address"],"properties":{"currency":{"$ref":"#/components/schemas/CurrencyId"},"network":{"$ref":"#/components/schemas/NetworkId"},"address":{"type":"string","minLength":1,"maxLength":4096},"memo":{"type":["string","null"],"maxLength":255}}},"AddressValidation":{"type":"object","required":["valid","checked","currency","network","memo","warnings"],"properties":{"valid":{"type":["boolean","null"],"description":"The network's address format rule; null when there is no rule for the network. Advisory: the source makes the binding check at creation."},"checked":{"type":"string","enum":["format"],"description":"What was checked (extensible)."},"currency":{"type":"string"},"network":{"type":"string"},"memo":{"type":"object","required":["supported","valid"],"properties":{"supported":{"type":"boolean"},"valid":{"type":["boolean","null"],"description":"false for a memo on a network without memos (POST /orders refuses it); otherwise null."}}},"warnings":{"$ref":"#/components/schemas/Warnings"}}},"Me":{"type":"object","required":["key","affiliate","rate_limit","usage_today","mock"],"properties":{"key":{"type":"object","required":["public_key","created_at","last_used_at"],"properties":{"public_key":{"type":"string","description":"The key's public id (not a secret).","pattern":"^ktv_pk_[0-9A-Za-z]{24}$"},"created_at":{"oneOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"last_used_at":{"oneOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}],"description":"Written at most every 5 minutes, so it may lag."}}},"affiliate":{"type":"object","required":["ref_code","status"],"properties":{"ref_code":{"type":["string","null"],"description":"Your referral code."},"status":{"type":"string","enum":["active"]}}},"rate_limit":{"type":"object","required":["limit","remaining","window_seconds","resets_at","weights"],"properties":{"limit":{"type":"integer","description":"Weight units per window."},"remaining":{"type":["integer","null"],"description":"After this request; null when it could not be read."},"window_seconds":{"type":"integer","examples":[60]},"resets_at":{"oneOf":[{"$ref":"#/components/schemas/Timestamp"},{"type":"null"}]},"weights":{"type":"object","required":["create_order","default"],"properties":{"create_order":{"type":"integer"},"default":{"type":"integer"}}}}},"usage_today":{"description":"The account's calls so far this UTC day (all keys); null when it could not be read.","oneOf":[{"type":"object","required":["quotes","orders","reads","validations","limited"],"properties":{"quotes":{"type":"integer"},"orders":{"type":"integer"},"reads":{"type":"integer"},"validations":{"type":"integer"},"limited":{"type":"integer","description":"Calls refused because the account's rate-limit budget was spent (429 `rate_limited` without `details.reason`)."}}},{"type":"null"}]},"mock":{"type":"boolean","description":"Always false on api.kotova.io."}}}},"parameters":{"Lang":{"name":"lang","in":"query","required":false,"description":"Language of the source notice (en default).","schema":{"$ref":"#/components/schemas/Lang"}},"OrderIdPath":{"name":"id","in":"path","required":true,"description":"The order id (`X-XXXXXX`, case-insensitive).","schema":{"type":"string","pattern":"^[Xx]-[A-Za-z0-9]{6}$"},"example":"X-7KQ2ZD"},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Recommended: 8-64 characters of A-Z a-z 0-9 _ - : . (a UUID fits). A retry with the same key and the same body answers the same order (201, `Idempotent-Replayed: true`) instead of creating a second one; the same key with a different body is 409 `idempotency_conflict`. Keys are kept 24 hours, per account. While the first request with a key is still running, a retry with it is 409 `idempotency_in_progress`: repeat it after `Retry-After`. Once that request has contacted a source it may run up to about 100 s after it arrived. If it was cut off there before its outcome was recorded, the source may hold the order: from then on the key answers 502 `source_error` with `reason: idempotency_outcome_unknown` (retryable false) for 24 hours. Do not place the order again under a new key; contact api@kotova.io with the request id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_\\-:.]{8,64}$"},"example":"3f1c9a52-7d0e-4b8a-9c61-2e5f4a7b8d90"}},"headers":{"X-Request-Id":{"description":"The request's id (`req_` + 24 letters and digits). Quote it to support.","schema":{"type":"string","pattern":"^req_[0-9A-Za-z]{24}$"}},"X-Kotova-Weight":{"description":"Weight units this request was charged (a refused request reports what it would have cost).","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The account budget: `\"units\";q=<limit>;w=60`.","schema":{"type":"string","examples":["\"units\";q=250;w=60"]}},"RateLimit":{"description":"Remaining units and seconds to the window's end: `\"units\";r=<remaining>;t=<seconds>`.","schema":{"type":"string","examples":["\"units\";r=249;t=34"]}},"X-RateLimit-Limit":{"description":"Weight units per 60-second window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Units left in this window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"Location":{"description":"The new order: `/x/v1/orders/{id}`.","schema":{"type":"string","examples":["/x/v1/orders/X-7KQ2ZD"]}},"Idempotent-Replayed":{"description":"Present (`true`) when this answer replays an earlier request with the same Idempotency-Key.","schema":{"type":"string","enum":["true"]}},"X-Kotova-Status-Refreshed":{"description":"Whether the order was refreshed from its source for this read (at most once per order per 10 s while it is in progress, once per 60 s while it is only followed up).","schema":{"type":"string","enum":["true","false"]}},"X-Kotova-Quote-Cache":{"description":"`hit`: the shared quote cache answered; `miss`: the sources were asked for this request.","schema":{"type":"string","enum":["hit","miss"]}},"ETag":{"description":"Weak validator of this answer; send it back as If-None-Match to get a 304.","schema":{"type":"string","examples":["W/\"394da0f044c4-5be2a7d1c09e\""]}},"Cache-Control":{"description":"CDN caching of this answer.","schema":{"type":"string"}},"WWW-Authenticate":{"description":"`Bearer realm=\"kotova-x\"`.","schema":{"type":"string","examples":["Bearer realm=\"kotova-x\""]}},"Last-Modified":{"description":"When the feed was built.","schema":{"type":"string"}},"X-Kotova-Feed-Status":{"description":"`ok`: every input is healthy and at least one rate is published; `degraded`: an input is missing (its rates are left out) or nothing is published.","schema":{"type":"string","enum":["ok","degraded"]}},"X-Kotova-Feed-Sources":{"description":"Comma-separated slugs of the sources whose rates are in the body, or `none`.","schema":{"type":"string","examples":["ccecash,ffio"]}},"X-Kotova-Feed-Generated-At":{"description":"When the feed was built (ISO-8601, milliseconds).","schema":{"type":"string","format":"date-time"}},"RatesETag":{"description":"Strong validator (`\"<16 hex>\"`); send it back as If-None-Match to get a 304.","schema":{"type":"string","examples":["\"9c1f0e4b7a2d6385\""]}}},"responses":{"NotModified":{"description":"Not modified: the If-None-Match value matches the current ETag. No body.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"}}},"KeylessInvalidRequest":{"description":"Unknown, repeated or invalid query parameter (keyless operations take none unless listed).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"Unknown query parameter \"limit\".","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"limit","reason":"unknown_parameter"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}},"KeylessRateLimited":{"description":"Too many calls from this IP (120 per minute reach the server; CDN hits do not count).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests from this address. Retry in 34 s.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"ip","limit":120,"remaining":0,"reset_seconds":34},"doc_url":"https://docs.kotova.io/x/api/errors#rate_limited"}}}}},"KeylessServiceUnavailable":{"description":"The API or its catalog is unavailable (`details.reason`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"catalog_missing":{"value":{"error":{"code":"service_unavailable","message":"The currency catalog is temporarily unavailable.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"catalog_missing"},"doc_url":"https://docs.kotova.io/x/api/errors#service_unavailable"}}},"disabled":{"value":{"error":{"code":"service_unavailable","message":"The Kotova X API is not enabled.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"disabled"},"doc_url":"https://docs.kotova.io/x/api/errors#service_unavailable"}}}}}}},"InvalidRequest":{"description":"The request is malformed: `details.field` names the field, `details.reason` says why.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"required":{"value":{"error":{"code":"invalid_request","message":"rate_type is required (fixed or variable).","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"rate_type","reason":"required"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"unknown_field":{"value":{"error":{"code":"invalid_request","message":"Unknown field \"refundAddress\".","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"refundAddress","reason":"unknown_field"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}},"unknown_parameter":{"value":{"error":{"code":"invalid_request","message":"Unknown query parameter \"key\".","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"field":"key","reason":"unknown_parameter"},"doc_url":"https://docs.kotova.io/x/api/errors#invalid_request"}}}}}}},"Unauthorized":{"description":"Missing, malformed or unknown key (`unauthorized`), or a revoked key (`key_revoked`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthorized":{"value":{"error":{"code":"unauthorized","message":"A valid API key is required: send it as Authorization: Bearer ktv_sk_….","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","doc_url":"https://docs.kotova.io/x/api/errors#unauthorized"}}},"key_revoked":{"value":{"error":{"code":"key_revoked","message":"This API key has been revoked. Create a new key on your Kotova account page.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","doc_url":"https://docs.kotova.io/x/api/errors#key_revoked"}}}}}}},"AffiliateInactive":{"description":"The key's account is not active.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"affiliate_inactive","message":"The account this API key belongs to is not active.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","doc_url":"https://docs.kotova.io/x/api/errors#affiliate_inactive"}}}}},"PayloadTooLarge":{"description":"The body is larger than 16 KB.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"payload_too_large","message":"The request body is too large.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"max_bytes":16384},"doc_url":"https://docs.kotova.io/x/api/errors#payload_too_large"}}}}},"UnsupportedMediaType":{"description":"The body is not sent as application/json.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unsupported_media_type","message":"The request body must be JSON (Content-Type: application/json).","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","doc_url":"https://docs.kotova.io/x/api/errors#unsupported_media_type"}}}}},"RateLimited":{"description":"The account budget is spent for this window (or, with `details.reason`, a sub-limit). Retry after `Retry-After` seconds; the refused call cost nothing.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"account":{"value":{"error":{"code":"rate_limited","message":"Rate limit of 250 units per 60 s reached. Retry in 34 s.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"limit":250,"remaining":0,"reset_seconds":34,"weight":1},"doc_url":"https://docs.kotova.io/x/api/errors#rate_limited"}}},"auth_failures":{"value":{"error":{"code":"rate_limited","message":"Too many failed authentications from this address. Retry in 34 s.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"auth_failures","limit":30,"remaining":0,"reset_seconds":34},"doc_url":"https://docs.kotova.io/x/api/errors#rate_limited"}}}}}}},"InternalError":{"description":"Unexpected server error.","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"internal_error","message":"An internal error occurred.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","doc_url":"https://docs.kotova.io/x/api/errors#internal_error"}}}}},"ServiceUnavailable":{"description":"The service is temporarily unavailable (`details.reason`).","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"},"X-Kotova-Weight":{"$ref":"#/components/headers/X-Kotova-Weight"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimit-Policy"},"RateLimit":{"$ref":"#/components/headers/RateLimit"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"service_unavailable","message":"The service is temporarily unavailable. Retry shortly.","request_id":"req_8fK2mQ9xLp3vTz7nWc1bYd4h","details":{"reason":"storage_unavailable"},"doc_url":"https://docs.kotova.io/x/api/errors#service_unavailable"}}}}}}}}