# Exchange

Sell a coin you hold and pay any of several thousand others out to an address

5 endpoints. Generated from `docs/openapi.yaml` v1.0.0.

| Endpoint | Summary |
| --- | --- |
| [`GET /v1/exchange/assets`](#get-v1-exchange-assets) | List the coins an exchange can buy |
| [`GET /v1/exchange/chains`](#get-v1-exchange-chains) | List the chains an exchange can pay out to |
| [`POST /v1/exchange/quote`](#post-v1-exchange-quote) | Price an exchange, and validate the destination address |
| [`POST /v1/exchange/orders`](#post-v1-exchange-orders) | Start an exchange — sell a held coin, pay another one out |
| [`GET /v1/swap/orders`](#get-v1-swap-orders) | List swap and exchange orders |

## GET /v1/exchange/assets

**List the coins an exchange can buy**  ·  _Auth: bearer API key_  ·  `operationId: listExchangeAssets`

The payout catalogue — thousands of coins across dozens of chains, refreshed
hourly from the router; `total` on this route is the live count. Far wider
than GET /v1/assets (the handful a user can HOLD with us). Nothing here is
custodial: these are payout destinations only.

`asset` is the EXCHANGE's own identifier (e.g. `SOL.SOL`,
`ETH.USDC-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) and is exactly what
`buy_asset` expects on POST /v1/exchange/quote and POST /v1/exchange/orders.
It is NOT one of our `asset_id` values — take it from here rather than
constructing it, because a value we cannot route is rejected outright.

`total` counts every match; `assets` is capped at `limit` (default 100), so
`total` greater than the array's length means "narrow the search", not
"there are only this many".

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `search` | query | `string` | no | Case-insensitive substring match on ticker, name or identifier. |
| `chain` | query | `string` | no | Exact chain, case-insensitive (e.g. `SOL`). Values from GET /v1/exchange/chains. |
| `limit` | query | `integer` | no | — _(default `100`; min `1`; max `500`)_ |

#### Responses

| Status | Body | Meaning |
| --- | --- | --- |
| `200` | `object` | Matching payout assets. |
| `401` | `Error` | Missing, malformed or unknown API key. |
| `403` | `Error` | Swaps and exchanges are turned off, or the exchange integration is not configured. |
| `502` | `Error` | The exchange failed or was unreachable (your request was valid). |

**`200` response body**

| Field | Type | Description |
| --- | --- | --- |
| `total` **required** | `integer` | Matches BEFORE `limit` was applied. |
| `assets` **required** | `object[]` | — |
| `assets[].asset` **required** | `string` | The EXCHANGE's identifier — what `buy_asset` expects. NOT one of our `asset_id` values, and not derivable from one. |
| `assets[].chain` **required** | `string` | Chain as the exchange names it — a wider set than our `Chain` enum. |
| `assets[].symbol` **required** | `string` | — |
| `assets[].name` **required** | `string` | — |
| `assets[].decimals` **required** | `integer` | The coin's own decimals, on a chain we do not model. Informational: we publish no base units for it, so amounts stay decimal strings. |
| `assets[].contract_address` **required** | `string | null` | Token contract, or null for a chain's native coin. |
| `assets[].logo_url` **required** | `string | null` | A path on this API that serves the coin's picture (`/v1/exchange/assets/{identifier}/logo`). Null when the coin has none. Fetch it with your API key like any other call; it is cacheable for a week. |

```json
{
  "total": 1,
  "assets": [
    {
      "asset": "ETH.USDC-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "chain": "ETH",
      "symbol": "USDC",
      "name": "USD Coin",
      "decimals": 1,
      "contract_address": "string",
      "logo_url": "string"
    }
  ]
}
```

#### Example request

```bash
curl -X GET 'https://api.cryptoinfra.build/v1/exchange/assets' \
  -H 'Authorization: Bearer ck_live_your_key'
```

## GET /v1/exchange/chains

**List the chains an exchange can pay out to**  ·  _Auth: bearer API key_  ·  `operationId: listExchangeChains`

The distinct chains present in the catalogue, sorted — for a picker's chain filter. Feed a value back as the `chain` query on GET /v1/exchange/assets.

#### Responses

| Status | Body | Meaning |
| --- | --- | --- |
| `200` | `object` | Payout chains. |
| `401` | `Error` | Missing, malformed or unknown API key. |
| `403` | `Error` | Swaps and exchanges are turned off, or the exchange integration is not configured. |
| `502` | `Error` | The exchange failed or was unreachable (your request was valid). |

**`200` response body**

| Field | Type | Description |
| --- | --- | --- |
| `chains` **required** | `string[]` | — |

```json
{
  "chains": [
    "SOL"
  ]
}
```

#### Example request

```bash
curl -X GET 'https://api.cryptoinfra.build/v1/exchange/chains' \
  -H 'Authorization: Bearer ck_live_your_key'
```

## POST /v1/exchange/quote

**Price an exchange, and validate the destination address**  ·  _Auth: bearer API key_  ·  `operationId: quoteExchange`

Indicative: confers no reservation and holds no balance. But it DOES validate
`destination_address`, and that is the reason to always call it first. We have
no address library for most of these chains, so the exchange is asked at quote
time; a bad address comes back as `400 invalid_pair` before anything is
charged. Quote before you create, and show the rejection to your customer.

The SELL side carries the usual `*_base` twin. The BUY side does not: the
coin's decimals belong to a chain we do not model, so `receive_estimate` and
`receive_minimum` are the exchange's own decimal strings. Render them as
given — never scale them by an asset of ours.

`receive_estimate` is an estimate; `receive_minimum` is the floor this route
guarantees. The customer is paid what ACTUALLY ARRIVES, which is why both are
published: the pair is the promise.

A quote is good for at most 60 seconds, or less when the route itself expires
sooner — `expires_at` carries the earlier of the two.

`destination_address` is optional here — omit it to price alone, send it and
it is validated too. It is required on POST /v1/exchange/orders.

#### Request body

`application/json` · required · schema `ExchangeQuoteRequest`

| Field | Type | Description |
| --- | --- | --- |
| `sell_asset_id` **required** | `string` | One of OUR assets (GET /v1/assets) — what is sold out of the user's balance. A disabled asset, or one with `swappable: false`, is refused with 400 invalid_pair (the message names it), exactly as on a swap. _(minLength `1`; maxLength `64`)_ |
| `buy_asset` **required** | `string` | The coin to buy, as the EXCHANGE's identifier — the `asset` field of GET /v1/exchange/assets, e.g. `SOL.SOL` or `ETH.USDC-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`. This is NOT one of our asset ids; anything we cannot route is rejected with 400 invalid_pair. _(minLength `1`; maxLength `128`)_ |
| `amount` **required** | `string | number` | Decimal amount of `sell_asset_id`, fee INCLUSIVE: our fee comes out of it and `send_amount` is what reaches the exchange. |
| `destination_address` | `string` | Where the bought coin is paid out. Must be valid on `buy_asset`'s chain. Optional on a quote — omit it to price alone, send it and the exchange validates it here too. Required on POST /v1/exchange/orders. We have no address library for most of these chains, so the exchange is asked at quote time and an invalid address is refused with 400 invalid_pair — before anything is charged. Once an order is created this payout is IRREVERSIBLE: the coin never enters our custody. _(minLength `1`; maxLength `256`)_ |

#### Responses

| Status | Body | Meaning |
| --- | --- | --- |
| `200` | `ExchangeQuote` | An indicative price, with the moment it stops being valid. |
| `400` | `Error` | The request was refused before anything was charged. `error` is one of: validation_error, invalid_amount, invalid_pair (`buy_asset` is not routable, the sell asset is disabled or no exchange can route it — `swappable: false` on GET /v1/assets, the message names it — both sides are the same coin, or `destination_address` is not valid for `buy_asset`'s chain), no_route (that pair has no liquidity path at this size — nothing is broken, try another amount or coin). |
| `401` | `Error` | Missing, malformed or unknown API key. |
| `403` | `Error` | Swaps and exchanges are turned off, or the exchange integration is not configured. |
| `502` | `Error` | The exchange failed or was unreachable (your request was valid). |
| `503` | `Error` | Our side is not ready for this chain. The request was fine — retry rather than change it. |

**`200` response body** — `ExchangeQuote`

| Field | Type | Description |
| --- | --- | --- |
| `sell_asset_id` **required** | `string` | — |
| `buy_asset` **required** | `string` | The exchange identifier you asked for, echoed back. |
| `buy_symbol` **required** | `string` | — |
| `buy_chain` **required** | `string` | — |
| `sell_amount` **required** | `string` | A monetary value as a decimal string. Always paired with a `*_base` field that carries the exact integer base-unit value; compute with the `_base` string. |
| `sell_amount_base` **required** | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `fee` **required** | `string` | Our fee, taken OUT of `sell_amount` — not charged on top. |
| `fee_base` **required** | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `send_amount` **required** | `string` | `sell_amount` minus `fee` — what reaches the exchange, published so the numbers add up. No `_base` twin here. |
| `receive_estimate` **required** | `string` | Estimated payout, as the EXCHANGE's decimal string on its own chain. Render as given; there is no `receive_estimate_base` for an exchange. |
| `receive_minimum` **required** | `string` | The floor this route guarantees, same encoding. The customer is credited what ARRIVES, not this — treat it as the worst case you may quote them. |
| `quoted_at` | `string<date-time>` | When this quote was priced; `expires_at` is how long the route stands. |
| `providers` **required** | `string[]` | The route's legs, in order. |
| `estimated_seconds` **required** | `integer | null` | — |
| `expires_at` **required** | `string<date-time>` | When the quote stops being valid. Same shape as the swap quote's. |

```json
{
  "sell_asset_id": "string",
  "buy_asset": "SOL.SOL",
  "buy_symbol": "SOL",
  "buy_chain": "SOL",
  "sell_amount": "1.5",
  "sell_amount_base": "1500000000",
  "fee": "1.5",
  "fee_base": "1500000000",
  "send_amount": "1.5",
  "receive_estimate": "0.4193",
  "receive_minimum": "0.4109",
  "quoted_at": "2026-08-31T09:15:00.000Z",
  "providers": [
    "string"
  ],
  "estimated_seconds": 1,
  "expires_at": "2026-08-31T04:21:00.000Z"
}
```

#### Example request

```bash
curl -X POST 'https://api.cryptoinfra.build/v1/exchange/quote' \
  -H 'Authorization: Bearer ck_live_your_key' \
  -H 'Content-Type: application/json' \
  -d '{
  "sell_asset_id": "usdt_trc20",
  "buy_asset": "SOL.SOL",
  "amount": "100"
}'
```

## POST /v1/exchange/orders

**Start an exchange — sell a held coin, pay another one out**  ·  _Auth: bearer API key_  ·  `operationId: createExchangeOrder`

`201`, and the user's balance is ALREADY debited: the sell leg is an ordinary
withdrawal, priced, signed and broadcast by the same code as any other payout.
Our fee comes out of the amount, and the withdrawal fee is NOT charged on top.

The bought coin is paid to `destination_address` and NEVER enters our custody.
It cannot be reversed and it cannot be recovered — the same finality as a
withdrawal, which is exactly what the sell leg is. POST /v1/exchange/quote is
the only validation that address gets, and it costs nothing: quote first.

Idempotent on `idempotency_key` — replaying returns the existing order instead
of starting a second one; the same key with a DIFFERENT payload is refused with
`409 idempotency_conflict`. Then poll GET /v1/swap/orders/{id}: `pending` until
the sell leg is on-chain, `sent`/`swapping` while the exchange works, and
`completed` once it reports the payout. Nothing is ever credited to the user's
balance; `received` is what landed at `destination_address`.

Buy-side amounts (`receive_estimate`, `receive_minimum`, `received`) are the
exchange's decimal strings and their `*_base` twins are null.

#### Request body

`application/json` · required · schema `ExchangeOrderRequest`

| Field | Type | Description |
| --- | --- | --- |
| `sell_asset_id` **required** | `string` | One of OUR assets (GET /v1/assets) — what is sold out of the user's balance. A disabled asset, or one with `swappable: false`, is refused with 400 invalid_pair (the message names it), exactly as on a swap. _(minLength `1`; maxLength `64`)_ |
| `buy_asset` **required** | `string` | The coin to buy, as the EXCHANGE's identifier — the `asset` field of GET /v1/exchange/assets, e.g. `SOL.SOL` or `ETH.USDC-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`. This is NOT one of our asset ids; anything we cannot route is rejected with 400 invalid_pair. _(minLength `1`; maxLength `128`)_ |
| `amount` **required** | `string | number` | Decimal amount of `sell_asset_id`, fee INCLUSIVE: our fee comes out of it and `send_amount` is what reaches the exchange. |
| `destination_address` **required** | `string` | Where the bought coin is paid out. Must be valid on `buy_asset`'s chain. Optional on a quote — omit it to price alone, send it and the exchange validates it here too. Required on POST /v1/exchange/orders. We have no address library for most of these chains, so the exchange is asked at quote time and an invalid address is refused with 400 invalid_pair — before anything is charged. Once an order is created this payout is IRREVERSIBLE: the coin never enters our custody. _(minLength `1`; maxLength `256`)_ |
| `user_id` **required** | `string` | Your `external_user_id` — whose balance is sold. _(minLength `1`)_ |
| `idempotency_key` | `string` | Replaying a key returns the existing order instead of starting a second one; the same key with a different payload is 409 idempotency_conflict. _(minLength `1`; maxLength `255`)_ |

#### Responses

| Status | Body | Meaning |
| --- | --- | --- |
| `201` | `SwapOrder` | Exchange started; the sell leg is queued as a withdrawal. |
| `400` | `Error` | The request was refused before anything was charged. `error` is one of: validation_error, invalid_amount, invalid_pair (`buy_asset` is not routable, the sell asset is disabled or no exchange can route it — `swappable: false` on GET /v1/assets, the message names it — both sides are the same coin, or `destination_address` is not valid for `buy_asset`'s chain), no_route (that pair has no liquidity path at this size — nothing is broken, try another amount or coin). |
| `401` | `Error` | Missing, malformed or unknown API key. |
| `403` | `Error` | Swaps and exchanges are turned off, or the exchange integration is not configured. |
| `404` | `Error` | Unknown external_user_id for this tenant. |
| `409` | `Error` | `error` is one of: insufficient_balance (the sell amount would overdraw the user's balance), idempotency_conflict (this `idempotency_key` was already used with a DIFFERENT payload — your replay is not the request you think it is). |
| `502` | `Error` | The exchange failed or was unreachable (your request was valid). |
| `503` | `Error` | Our side is not ready for this chain. The request was fine — retry rather than change it. |

**`201` response body** — `SwapOrder`

| Field | Type | Description |
| --- | --- | --- |
| `order_id` **required** | `string<uuid>` | — |
| `user_id` | `string` | Your `external_user_id`. Present on create; absent when listing or fetching. |
| `kind` **required** | `string` | `swap` buys one of OUR assets: the output lands on the user's own deposit address and is credited to their balance. `exchange` buys a coin we do not custody: the output is paid to `destination_address` and never enters our system. _(one of `swap`, `exchange`)_ |
| `sell_asset_id` **required** | `string` | — |
| `buy_asset_id` **required** | `string | null` | One of our assets on a swap; null on an exchange (we have no asset row for it). |
| `buy_asset_external` **required** | `string | null` | The exchange's identifier on an exchange (e.g. `SOL.SOL`); null on a swap. |
| `buy_symbol` **required** | `string | null` | Display ticker of the bought coin on an exchange, so a listing needs no catalogue lookup. Null on a swap. |
| `buy_chain` **required** | `string | null` | Chain of the bought coin on an exchange, as the exchange names it. Null on a swap. |
| `destination_address` | `string` | Where the bought coin was paid. Present on EXCHANGE rows ONLY — echoed back so you can confirm it — and absent on a swap, whose output goes to the user's own static wallet address. This payout is irreversible and outside our custody. |
| `sell_amount` **required** | `string` | A monetary value as a decimal string. Always paired with a `*_base` field that carries the exact integer base-unit value; compute with the `_base` string. |
| `sell_amount_base` **required** | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `fee` **required** | `string` | Our fee, taken out of `sell_amount` — a percentage with a dollar minimum (see GET /v1/pricing), plus `network_fee`. |
| `fee_base` **required** | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `network_fee` | `string` | The network part of `fee`, in the sold asset — a USDT ⇄ TRX trade's own gas on TRON, or an exchange's send. Already inside `fee`. |
| `network_fee_base` | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `receive_estimate` | `string | null` | What the route estimated. A swap's is in the buy asset's major units; an exchange's is the exchange's decimal string. |
| `receive_estimate_base` | `string | null` | Exact base units on a SWAP. Always null on an exchange. |
| `receive_minimum` | `string | null` | The floor the route guaranteed. The user is credited what arrives, not this. |
| `receive_minimum_base` | `string | null` | Exact base units on a SWAP. Always null on an exchange. |
| `received` | `string | null` | What ACTUALLY arrived. Null until the exchange settles. |
| `received_base` | `string | null` | Exact base units on a SWAP. Always null on an exchange. |
| `providers` **required** | `string[]` | — |
| `status` **required** | `string` | `pending` until the sell leg is on-chain, then `sent` and `swapping` while the exchange works; `completed` when it reports the payout. _(one of `pending`, `sent`, `swapping`, `completed`, `refunded`, `failed`)_ |
| `tracking_status` | `string | null` | The exchange's own last word on the route, verbatim. Informational. |
| `txid` | `string | null` | The on-chain SELL payment that started the order — the handle to show a customer, and the one the exchange's tracker keys on. Null until it is sent. |
| `created_at` **required** | `string<date-time>` | — |
| `updated_at` **required** | `string<date-time>` | — |

```json
{
  "order_id": "string",
  "user_id": "string",
  "kind": "swap",
  "sell_asset_id": "string",
  "buy_asset_id": "string",
  "buy_asset_external": "string",
  "buy_symbol": "string",
  "buy_chain": "string",
  "destination_address": "string",
  "sell_amount": "1.5",
  "sell_amount_base": "1500000000",
  "fee": "1.5",
  "fee_base": "1500000000",
  "network_fee": "1.5",
  "network_fee_base": "1500000000",
  "receive_estimate": "string",
  "receive_estimate_base": "string",
  "receive_minimum": "string",
  "receive_minimum_base": "string",
  "received": "string",
  "received_base": "string",
  "providers": [
    "string"
  ],
  "status": "pending",
  "tracking_status": "string",
  "txid": "string",
  "created_at": "2026-08-31T09:15:00.000Z",
  "updated_at": "2026-08-31T09:15:00.000Z"
}
```

#### Example request

```bash
curl -X POST 'https://api.cryptoinfra.build/v1/exchange/orders' \
  -H 'Authorization: Bearer ck_live_your_key' \
  -H 'Content-Type: application/json' \
  -d '{
  "sell_asset_id": "usdt_trc20",
  "buy_asset": "SOL.SOL",
  "amount": "100",
  "destination_address": "string",
  "user_id": "string"
}'
```

## GET /v1/swap/orders

**List swap and exchange orders**  ·  _Auth: bearer API key_  ·  `operationId: listSwapOrders`

Newest-first, scoped to your merchant. Swaps and exchanges share ONE order
list and one order shape; `kind` filters between them.

A `swap` names one of our assets on both sides and credits the user's balance.
An `exchange` names its buy side by the exchange's identifier
(`buy_asset_external`, with `buy_symbol` and `buy_chain` so a listing needs no
catalogue lookup) and pays out to `destination_address`, which is echoed on
exchange rows only. On an exchange `buy_asset_id` is null, and every buy-side
`*_base` field is null with it — those decimals belong to a chain we do not
model, so there are no base units of ours to publish.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `kind` | query | `string` | no | Return only swaps, or only exchanges. Omit for both. _(one of `swap`, `exchange`)_ |
| `status` | query | `string` | no | — _(one of `pending`, `sent`, `swapping`, `completed`, `refunded`, `failed`)_ |
| `limit` | query | `integer` | no | — _(default `50`; min `1`; max `200`)_ |
| `offset` | query | `integer` | no | — _(default `0`; min `0`)_ |

#### Responses

| Status | Body | Meaning |
| --- | --- | --- |
| `200` | `object` | Matching orders. |
| `401` | `Error` | Missing, malformed or unknown API key. |

**`200` response body**

| Field | Type | Description |
| --- | --- | --- |
| `orders` **required** | `object[]` | — |
| `orders[].order_id` **required** | `string<uuid>` | — |
| `orders[].user_id` | `string` | Your `external_user_id`. Present on create; absent when listing or fetching. |
| `orders[].kind` **required** | `string` | `swap` buys one of OUR assets: the output lands on the user's own deposit address and is credited to their balance. `exchange` buys a coin we do not custody: the output is paid to `destination_address` and never enters our system. _(one of `swap`, `exchange`)_ |
| `orders[].sell_asset_id` **required** | `string` | — |
| `orders[].buy_asset_id` **required** | `string | null` | One of our assets on a swap; null on an exchange (we have no asset row for it). |
| `orders[].buy_asset_external` **required** | `string | null` | The exchange's identifier on an exchange (e.g. `SOL.SOL`); null on a swap. |
| `orders[].buy_symbol` **required** | `string | null` | Display ticker of the bought coin on an exchange, so a listing needs no catalogue lookup. Null on a swap. |
| `orders[].buy_chain` **required** | `string | null` | Chain of the bought coin on an exchange, as the exchange names it. Null on a swap. |
| `orders[].destination_address` | `string` | Where the bought coin was paid. Present on EXCHANGE rows ONLY — echoed back so you can confirm it — and absent on a swap, whose output goes to the user's own static wallet address. This payout is irreversible and outside our custody. |
| `orders[].sell_amount` **required** | `string` | A monetary value as a decimal string. Always paired with a `*_base` field that carries the exact integer base-unit value; compute with the `_base` string. |
| `orders[].sell_amount_base` **required** | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `orders[].fee` **required** | `string` | Our fee, taken out of `sell_amount` — a percentage with a dollar minimum (see GET /v1/pricing), plus `network_fee`. |
| `orders[].fee_base` **required** | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `orders[].network_fee` | `string` | The network part of `fee`, in the sold asset — a USDT ⇄ TRX trade's own gas on TRON, or an exchange's send. Already inside `fee`. |
| `orders[].network_fee_base` | `string` | Exact integer amount in the asset's smallest unit. _(pattern `^[0-9]+$`)_ |
| `orders[].receive_estimate` | `string | null` | What the route estimated. A swap's is in the buy asset's major units; an exchange's is the exchange's decimal string. |
| `orders[].receive_estimate_base` | `string | null` | Exact base units on a SWAP. Always null on an exchange. |
| `orders[].receive_minimum` | `string | null` | The floor the route guaranteed. The user is credited what arrives, not this. |
| `orders[].receive_minimum_base` | `string | null` | Exact base units on a SWAP. Always null on an exchange. |
| `orders[].received` | `string | null` | What ACTUALLY arrived. Null until the exchange settles. |
| `orders[].received_base` | `string | null` | Exact base units on a SWAP. Always null on an exchange. |
| `orders[].providers` **required** | `string[]` | — |
| `orders[].status` **required** | `string` | `pending` until the sell leg is on-chain, then `sent` and `swapping` while the exchange works; `completed` when it reports the payout. _(one of `pending`, `sent`, `swapping`, `completed`, `refunded`, `failed`)_ |
| `orders[].tracking_status` | `string | null` | The exchange's own last word on the route, verbatim. Informational. |
| `orders[].txid` | `string | null` | The on-chain SELL payment that started the order — the handle to show a customer, and the one the exchange's tracker keys on. Null until it is sent. |
| `orders[].created_at` **required** | `string<date-time>` | — |
| `orders[].updated_at` **required** | `string<date-time>` | — |

```json
{
  "orders": [
    {
      "order_id": "string",
      "user_id": "string",
      "kind": "swap",
      "sell_asset_id": "string",
      "buy_asset_id": "string",
      "buy_asset_external": "string",
      "buy_symbol": "string",
      "buy_chain": "string",
      "destination_address": "string",
      "sell_amount": "1.5",
      "sell_amount_base": "1500000000",
      "fee": "1.5",
      "fee_base": "1500000000",
      "network_fee": "1.5",
      "network_fee_base": "1500000000",
      "receive_estimate": "string",
      "receive_estimate_base": "string",
      "receive_minimum": "string",
      "receive_minimum_base": "string",
      "received": "string",
      "received_base": "string",
      "providers": [
        "string"
      ],
      "status": "pending",
      "tracking_status": "string",
      "txid": "string",
      "created_at": "2026-08-31T09:15:00.000Z",
      "updated_at": "2026-08-31T09:15:00.000Z"
    }
  ]
}
```

#### Example request

```bash
curl -X GET 'https://api.cryptoinfra.build/v1/swap/orders' \
  -H 'Authorization: Bearer ck_live_your_key'
```
