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

# Build

## Build

Turns a swap into unsigned transactions. The pools are re-read on fresh network state, the swap is simulated, and the answer is a fresh quote plus `steps[]` — one unsigned `transaction` per step, in the network's own format, for your wallet to sign and send in order. Charged 10,000 credits per call ([Billing](/getting-started/billing.md)).

`from_address` is required. Everything else works as in [`POST /v1/quote`](/api-reference/quote.md).

#### **Build**

<mark style="color:green;">`POST`</mark> `https://swap-api.crypto-chief.com/YOUR_API_KEY/v1/build`

**Headers**

| Name         | Value                                                                                                           |
| ------------ | --------------------------------------------------------------------------------------------------------------- |
| Content-Type | `application/json`                                                                                              |
| X-Request-Id | Optional — your id for this call, echoed in the response ([Authentication](/getting-started/authentication.md)) |

**Body**

All fields of [`POST /v1/quote`](/api-reference/quote.md), plus:

| Name                 | Type      | Required | Description                                                                                                                                                                                                                                                  |
| -------------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `from_address`       | string    | true     | The wallet that signs the steps. Its balance, allowance, trust lines and token accounts are checked                                                                                                                                                          |
| `recipient`          | string    | false    | Receiver of the output. Default `from_address`. `400 INVALID_REQUEST` if it is the executor's address, its spender, Permit2, the wrapped native token, the native-coin placeholder, or a token of the deal. Solana and XRP Ledger: only `from_address`       |
| `deadline_seconds`   | integer   | false    | How long the swap transaction stays valid, in seconds: `1`–`86400` (TON `10`–`86400`), otherwise `400 INVALID_REQUEST`. Default `120`. Counted from network time: `max(time of the last block, the API's clock) + deadline_seconds`. Not applied on Solana   |
| `approve_mode`       | string    | false    | `exact` (default) — approve the swap amount; `unlimited` — no cap on the allowance                                                                                                                                                                           |
| `quote_id`           | string    | false    | Build the route and executor of this quote while they fit this request and stay best ([the rule](/getting-started/how-a-swap-works.md#quote-vs-build)). Expired or unknown: the build searches afresh, with a warning. Not a valid id: `400 INVALID_REQUEST` |
| `executed_tx_hashes` | string\[] | false    | EVM / TRON, with `allow_non_atomic`: hashes of this deal's transactions you already sent, at most 16. See [Non-atomic routes](/getting-started/how-a-swap-works.md#non-atomic-routes). Solana, TON and XRP Ledger ignore the field                           |

```json
{
  "network": "ETH_MAINNET",
  "token_in": "USDC",
  "token_out": "NATIVE",
  "amount_in": "1000000000",
  "from_address": "0x1F33F99676B65968885adDFaFda3a736424d93C9",
  "slippage_bps": 50,
  "quote_id": "0b6f8c7e-6a43-4d0a-9d7e-3c2f5a1e9b10"
}
```

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "quote_id": "0b6f8c7e-6a43-4d0a-9d7e-3c2f5a1e9b10",
  "network": "ETH_MAINNET",
  "family": "EVM",
  "token_in": {"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "symbol": "USDC", "decimals": 6, "kind": "token", "flags": ["pausable", "blacklist"]},
  "token_out": {"address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", "symbol": "ETH", "decimals": 18, "kind": "native"},
  "amount_in": "1000000000",
  "amount_in_human": "1000",
  "amount_out": "263157894736842105",
  "amount_out_human": "0.263157894736842105",
  "amount_out_min": "261842105263157894",
  "amount_out_min_human": "0.261842105263157894",
  "slippage_bps": 50,
  "net_amount_out": "261636578947368421",
  "price_impact_bps": 4,
  "fees": {
    "network": {
      "native_symbol": "ETH",
      "cost_native": "1495000000000000",
      "cost_native_human": "0.001495",
      "cost_in_token_out": "1495000000000000",
      "cost_usd": "5.68",
      "gas_limit": 180000,
      "unit_price": "12000000000",
      "effective_unit_price": "6500000000",
      "details": {"gas_units": "230000", "gas_price": "6500000000", "max_cost_wei": "2760000000000000"}
    },
    "pools": [
      {"source": "uniswap_v3", "pool": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640", "fee_bps": 5.0, "fee_amount": "300000", "fee_token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"},
      {"source": "sushi_v2", "pool": "0x397FF1542f962076d0BFE58eA045FfA2d347ACa0", "fee_bps": 30.0, "fee_amount": "1200000", "fee_token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"}
    ],
    "service": {"bps": 0, "amount": "0"}
  },
  "route": {
    "splits": [
      {
        "share_bps": 6000,
        "amount_in": "600000000",
        "amount_out": "157894736842105263",
        "hops": [
          {"source": "uniswap_v3", "pool": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640", "kind": "uni_v3", "token_in": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "token_out": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "fee_bps": 5.0, "amount_in": "600000000", "amount_out": "157894736842105263"}
        ]
      },
      {
        "share_bps": 4000,
        "amount_in": "400000000",
        "amount_out": "105263157894736842",
        "hops": [
          {"source": "sushi_v2", "pool": "0x397FF1542f962076d0BFE58eA045FfA2d347ACa0", "kind": "uni_v2", "token_in": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "token_out": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "fee_bps": 30.0, "amount_in": "400000000", "amount_out": "105263157894736842"}
        ]
      }
    ]
  },
  "executor": {"id": "sushi_rp5", "address": "0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55", "atomic": true, "third_party": true, "onchain_deadline": false, "transactions": 2},
  "risk": {
    "level": "low",
    "score": 12,
    "penalty": "26315789473684",
    "factors": [
      {"code": "third_party_router", "level": "low", "message": "executor contract is controlled by a third party", "cost": "26315789473684"},
      {"code": "setup_required", "level": "low", "message": "approve USDC before the swap"},
      {"code": "simulation_not_run", "level": "low", "message": "simulation did not run: allowance is lower than amount_in"}
    ]
  },
  "setup_required": true,
  "state": {"reference": 23651200, "age_ms": 1800},
  "expires_at": "2026-10-25T12:00:30Z",
  "search": {"engine": "native", "paths_considered": 18, "pools_considered": 42, "elapsed_ms": 21, "truncated": false},
  "recipient": "0x1F33F99676B65968885adDFaFda3a736424d93C9",
  "steps": [
    {
      "index": 0,
      "kind": "approve",
      "description": "Approve 1000 USDC to 0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55",
      "calls": [
        {"to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "value": "0", "data": "0x095ea7b3000000000000000000000000f2614a233c7c3e7f08b1f887ba133a13f1eb2c55000000000000000000000000000000000000000000000000000000003b9aca00"}
      ],
      "transaction": {
        "from": "0x1F33F99676B65968885adDFaFda3a736424d93C9",
        "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "data": "0x095ea7b3000000000000000000000000f2614a233c7c3e7f08b1f887ba133a13f1eb2c55000000000000000000000000000000000000000000000000000000003b9aca00",
        "value": "0x0",
        "chainId": "0x1",
        "type": "0x2",
        "maxFeePerGas": "0x2cb417800",
        "maxPriorityFeePerGas": "0x3b9aca00"
      },
      "signer_supported": true,
      "wait_for_confirmation": true,
      "rebuild_after_previous": false
    },
    {
      "index": 1,
      "kind": "swap",
      "description": "Swap 1000 USDC for at least 0.261842105263157894 ETH via sushi_rp5",
      "calls": [{"to": "0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55", "value": "0", "data": "0x…"}],
      "transaction": {
        "from": "0x1F33F99676B65968885adDFaFda3a736424d93C9",
        "to": "0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55",
        "data": "0x…",
        "value": "0x0",
        "chainId": "0x1",
        "type": "0x2",
        "maxFeePerGas": "0x2cb417800",
        "maxPriorityFeePerGas": "0x3b9aca00"
      },
      "signer_supported": true,
      "wait_for_confirmation": true,
      "rebuild_after_previous": true
    }
  ],
  "simulation": {"status": "not_run", "reason": "allowance is lower than amount_in"}
}
```

This is the first build of an EVM swap whose allowance is still missing: an `approve` step, then a `swap` step that must not be signed yet — `rebuild_after_previous: true`. After the approve confirms, a second build returns one `swap` step with `rebuild_after_previous: false` and `simulation.status: "passed"`. See [How a Swap Works](/getting-started/how-a-swap-works.md#executing-the-steps).
{% endtab %}

{% tab title="422 SIMULATION\_FAILED" %}

```json
{
  "error": "SIMULATION_FAILED",
  "message": "simulation failed: tecPATH_PARTIAL: Path could not send partial amount."
}
```

No steps are issued. The swap would fail on chain in the current state — the per-family rules are [below](#simulation-per-network).
{% endtab %}

{% tab title="422 BALANCE\_INSUFFICIENT" %}

```json
{
  "error": "BALANCE_INSUFFICIENT",
  "message": "from_address cannot spend 100 XRP after reserving 0.2 XRP for the new trust line"
}
```

`from_address` cannot cover the input, the network fees and reserves. When no route can be assembled, this error comes before `SIMULATION_FAILED`. Solana reports insufficient funds differently ([Simulation](/getting-started/how-a-swap-works.md#simulation)).
{% endtab %}

{% tab title="503" %}

```json
{
  "error": "STATE_STALE",
  "message": "transaction 0xb2c1…d4e5 has no receipt yet; retry once it is confirmed"
}
```

While continuing a non-atomic deal, the previous swap is not visible on chain yet. Retry once it confirms, or pass its hash in `executed_tx_hashes`. [Non-atomic routes](/getting-started/how-a-swap-works.md#non-atomic-routes).
{% endtab %}
{% endtabs %}

**Fields**

Everything a [quote](/api-reference/quote.md) returns, with current amounts, plus:

| Field        | Description                                                                                                                                                                                                                                          |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `recipient`  | Who receives the output                                                                                                                                                                                                                              |
| `deadline`   | The swap transaction's expiry (RFC 3339), present only when every executor of the route checks it on chain — `executor.onchain_deadline` says which. The first swap's deadline; each next swap of a non-atomic route gets another `deadline_seconds` |
| `steps[]`    | The steps, in order — below                                                                                                                                                                                                                          |
| `simulation` | The swap step's simulation — below                                                                                                                                                                                                                   |

### The step object

| Field                    | Description                                                                                                                                         |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `index`                  | Position, from 0                                                                                                                                    |
| `kind`                   | `approve_reset`, `approve`, `permit2_approve`, `trust_set`, `swap` — [what each is](/getting-started/how-a-swap-works.md#setup-steps)               |
| `description`            | What the step does, in words                                                                                                                        |
| `calls[]`                | The transaction's calls — per family below                                                                                                          |
| `transaction`            | The unsigned transaction in the network's own format — per family below                                                                             |
| `signer_supported`       | Always `true` in these responses; ignore it                                                                                                         |
| `wait_for_confirmation`  | Wait for this step to confirm on chain before signing the next one                                                                                  |
| `rebuild_after_previous` | Do not sign this step. Call `/v1/build` again with the same parameters after the previous step confirms, and continue with the new response's steps |

**`calls[]`** per family:

| Family     | A call is                                                                                                                               |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| EVM        | One `{to, value (wei), data (0x hex)}`                                                                                                  |
| TRON       | One `{to (base58), value (sun), data (hex)}`                                                                                            |
| Solana     | Several instructions `{to: program_id, data: base64, accounts: [{address, is_signer, is_writable}]}`; the only signer is `from_address` |
| TON        | One message `{to, value (nanoTON), data (base64 BoC: the serialized message cell), bounce}`                                             |
| XRP Ledger | `{tx_json}` — an unsigned `TrustSet`, `Payment` or `Batch`                                                                              |

### The transaction formats

Every step carries `transaction`, an unsigned transaction in the network's own format. [Signing on Each Network](/guides/signing.md) shows the signing code for each.

{% tabs %}
{% tab title="EVM" %}
A JSON-RPC transaction object for `eth_sendTransaction`: `from`, `to`, `data`, `value`, `chainId`, and EIP-1559 (`type: "0x2"` with `maxFeePerGas` and `maxPriorityFeePerGas`) or legacy (`type: "0x0"` with `gasPrice`). Addresses are checksummed, quantities are `0x` hex without leading zeros, and there is no `nonce` — the wallet sets it.

```json
{
  "from": "0x1F33F99676B65968885adDFaFda3a736424d93C9",
  "to": "0xf2614A233c7C3e7f08b1F887Ba133a13f1eb2c55",
  "data": "0x…",
  "value": "0x0",
  "gas": "0x2bf20",
  "chainId": "0x1",
  "type": "0x2",
  "maxFeePerGas": "0x2cb417800",
  "maxPriorityFeePerGas": "0x3b9aca00"
}
```

A browser wallet takes this object as is: `window.ethereum.request({method: "eth_sendTransaction", params: [tx]})`. Libraries want their own field names — ethers v6 takes `gasLimit` (not `gas`) and a numeric `type`; see [Signing on Each Network](/guides/signing.md#evm).

{% hint style="warning" %}
`gas` is present only when the API measured the step — the value includes headroom for re-execution. Without `gas` the wallet estimates the limit, which is typical for the swap right after an approve (that step also carries `rebuild_after_previous: true`, and the rebuild is where the measurement happens).
{% endhint %}
{% endtab %}

{% tab title="TRON" %}
The body of `/wallet/triggersmartcontract`: `owner_address`, `contract_address` (Base58Check), `data` (the full calldata, hex without `0x`), `call_value`, `fee_limit` (sun), `visible: true`.

```json
{
  "owner_address": "TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf",
  "contract_address": "TQqgNg13s2DjvXhW1ky4v6TsR8wZGvb7Y4",
  "data": "3593564c…",
  "call_value": 0,
  "fee_limit": 24000000,
  "visible": true
}
```

With TronWeb: `transactionBuilder.triggerSmartContract(contract_address, "", {input: data, callValue: call_value, feeLimit: fee_limit}, [], owner_address)`, then `trx.sign` and `trx.sendRawTransaction` — the full snippet is in [Signing on Each Network](/guides/signing.md#tron).

`fee_limit` comes from the step's energy estimate, capped at 100 TRX; a capped limit adds a warning and the risk factor `fee_limit_capped`, because the swap can fail with `OUT_OF_ENERGY`.

The executor `sun_universal_router` pulls the input through Permit2: the build starts with an `approve` of the token to the Permit2 contract, then a `permit2_approve` (`Permit2.approve(token, router, amount, expiration)`). Both are ordinary transactions in this same format ([when they are skipped](/getting-started/how-a-swap-works.md#setup-steps)). With the `dex_router` executor (SunSwap V2/V3) the steps are the EVM-like `approve` and `swap`.
{% endtab %}

{% tab title="Solana" %}

```json
{
  "encoding": "base64",
  "transaction": "<unsigned transaction: signature count, a zero signature, the message>",
  "version": 0,
  "last_valid_block_height": 438959582
}
```

Every transaction starts with the compute-budget instructions (`SetComputeUnitLimit` from the simulation, `SetComputeUnitPrice`). A version `0` transaction also carries the route's lookup tables (address tables the transaction references instead of listing every account); `"legacy"` is used when no table helps. The fee payer and only signer is `from_address`. Decode with `VersionedTransaction.deserialize(Buffer.from(transaction, "base64"))`, sign, send, and confirm against `last_valid_block_height` — about 60–90 seconds of validity. `deadline_seconds` does not apply on Solana.

{% hint style="warning" %}
**Do not add your own compute-budget instructions.** The transaction already carries them; a second pair is a different, larger transaction than the one simulated.
{% endhint %}

The output token account (the account that holds one token for one wallet) is created by an instruction inside the same transaction. If no fresh blockhash is available, the build answers `503 RPC_UNAVAILABLE`. A build without `quote_id` searches with a larger account budget than the quote did and can find a better route; a build with `quote_id` uses the quote's route.
{% endtab %}

{% tab title="TON" %}
A TON Connect request, passed to `tonConnectUI.sendTransaction` as is:

```json
{
  "validUntil": 1793000120,
  "network": "-239",
  "from": "0:1111111111111111111111111111111111111111111111111111111111111111",
  "messages": [
    {"address": "EQCSIMGBps_qzRG3uPYhON8bucyCtu0mYdL1-u4gSz77IBa3", "amount": "300000000", "payload": "te6cckEBAgEAqwAB…"}
  ]
}
```

`validUntil` is the swap deadline; `network` is `"-239"` (mainnet); `from` is your wallet in raw form. Each message has `address` (user-friendly — the bounce flag is inside the address), `amount` in nanoTON, and `payload` (base64 BoC). Keep `deadline_seconds` at most `300` ([why](/getting-started/how-a-swap-works.md#deadlines-per-network)). A server wallet signs the same message with `@ton/ton`; see [Signing on Each Network](/guides/signing.md#ton).

For a jetton input, the message's `address` is **your** jetton wallet and `amount` is TON for gas (the excess comes back). For a TON input, `amount` is the swap amount plus gas. The output arrives in later messages: a rejected swap returns your input; a rejected second hop leaves the intermediate token with the recipient (risk factor `async_settlement`).
{% endtab %}

{% tab title="XRP Ledger" %}
`transaction` is the step's `tx_json`: a `TrustSet`, a `Payment` to yourself with `SendMax`, `DeliverMin` and the partial-payment flag (`Flags: 131072`), or a `Batch` when a [partner fee](/getting-started/partner-fees.md) is set. `Account`, `Fee`, `Sequence` and `LastLedgerSequence` are filled — sign it as is (xrpl.js `Wallet.sign`, then `client.submitAndWait`):

```json
{
  "TransactionType": "Payment",
  "Account": "rBETHiaxrJYjJgAmqwtKMLqQ4aSRiGYN3b",
  "Destination": "rBETHiaxrJYjJgAmqwtKMLqQ4aSRiGYN3b",
  "Amount": {"currency": "524C555344000000000000000000000000000000", "issuer": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De", "value": "254.9907566391524"},
  "SendMax": "100000000",
  "DeliverMin": {"currency": "524C555344000000000000000000000000000000", "issuer": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De", "value": "253.71580285595664"},
  "Flags": 131072,
  "Paths": [[{"currency": "524C555344000000000000000000000000000000", "issuer": "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De"}]],
  "Fee": "15",
  "Sequence": 130985210,
  "LastLedgerSequence": 107875441
}
```

To refresh `Fee`, `Sequence` or `LastLedgerSequence`, remove them (in a `Batch`, also the inner transactions' `Sequence`) and run the wallet's autofill again — xrpl.js autofill keeps filled fields.

`DeliverMin` is `amount_out_min` in the ledger's own format. `Amount` is the upper bound of the output; what you actually receive is between `DeliverMin` and `Amount`, and the exact figure is the `delivered_amount` of the validated transaction. `LastLedgerSequence` is the validated ledger plus 35 — about 120 seconds; past it, rebuild. A new trust line reserves 0.2 XRP while it exists (`fees.network.details.reserve_xrp`). An issuer's transfer fees show in `fees.other` (`issuer_transfer_fee`, `issuer_transfer_fee_output`, `issuer_transfer_fee_partner`).
{% endtab %}
{% endtabs %}

### Simulation per network

`simulation` holds the swap step's simulation: `status` (`passed`, `incomplete`, `not_run`; a failure is `422 SIMULATION_FAILED` without steps, [the rule](/getting-started/how-a-swap-works.md#simulation)), `method`, `reference` (block / slot / ledger), `resources_used` (gas, energy, compute units), `amount_out` (the simulated output), `reason` (for `not_run` / `incomplete`).

| Family     | Rule                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| EVM        | `amount_out` and `amount_out_min` follow a passed simulation in both directions. Zero output, a shrinking recipient balance, or output below `amount_out × (1 − slippage)` rejects the route; a shortfall within tolerance adds a warning and the factor `simulation_below_quote`, with the amounts recomputed from the simulation. No route assembles → `422 SIMULATION_FAILED`. A route through unloaded pool ranges without a measured output → `503 STATE_INCOMPLETE` |
| TRON       | The same for the `dex_router` executor (its output is measured by simulation). `sun_universal_router` returns no output, so simulation does not measure it: the minimum stays from the local quote                                                                                                                                                                                                                                                                        |
| Solana     | A transaction error in simulation, output below the minimum, or a fee account that received more than `fee_bps` of the output → `422 SIMULATION_FAILED`, no steps. `not_run` and `incomplete` arrive as a `200` with steps and the factor `simulation_not_run`                                                                                                                                                                                                            |
| TON        | The minimum is the lower of the local quote and the DEX's estimate; an estimate below the local quote by more than max(10 bps, slippage) → `422 SIMULATION_FAILED`                                                                                                                                                                                                                                                                                                        |
| XRP Ledger | A failed simulation (a result other than `tesSUCCESS`) → `422 SIMULATION_FAILED`, no steps; a simulated output more than 50 bps below the path-finding estimate → a warning                                                                                                                                                                                                                                                                                               |

`fees.network.details` in a build carries the totals over all steps (EVM: `gas_units`, `l1_fee`, `max_cost_wei`; TRON: `energy`, `bandwidth`) plus the first swap's own estimate under `swap_*` keys (`swap_gas_used`, `swap_gas_source`, `swap_max_cost_wei`; TRON: `swap_energy`, `swap_fee_limit_sun`, ...) and `effective_gas_price_wei` at the top level.

### Example

`swap()` is defined in [Authentication](/getting-started/authentication.md).

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const build = await swap("build", {
  network: "ETH_MAINNET",
  token_in: "USDC",
  token_out: "NATIVE",
  amount_in: "1000000000",
  from_address: "0x1F33F99676B65968885adDFaFda3a736424d93C9",
  quote_id: "0b6f8c7e-6a43-4d0a-9d7e-3c2f5a1e9b10",
});
for (const step of build.steps) {
  console.log(step.index, step.kind, step.description);
}
```

{% endtab %}

{% tab title="PHP" %}

```php
$build = swap('build', [
    'network'      => 'ETH_MAINNET',
    'token_in'     => 'USDC',
    'token_out'    => 'NATIVE',
    'amount_in'    => '1000000000',
    'from_address' => '0x1F33F99676B65968885adDFaFda3a736424d93C9',
    'quote_id'     => '0b6f8c7e-6a43-4d0a-9d7e-3c2f5a1e9b10',
]);
foreach ($build['steps'] as $step) {
    echo $step['index'], ' ', $step['kind'], ' ', $step['description'], "\n";
}
```

{% endtab %}

{% tab title="GO" %}

```go
build, _, err := swap("build", map[string]any{
	"network":      "ETH_MAINNET",
	"token_in":     "USDC",
	"token_out":    "NATIVE",
	"amount_in":    "1000000000",
	"from_address": "0x1F33F99676B65968885adDFaFda3a736424d93C9",
	"quote_id":     "0b6f8c7e-6a43-4d0a-9d7e-3c2f5a1e9b10",
})
if err != nil {
	log.Fatal(err)
}
for _, step := range build["steps"].([]any) {
	s := step.(map[string]any)
	fmt.Println(s["index"], s["kind"], s["description"])
}
```

{% endtab %}

{% tab title="Python" %}

```python
build = swap("build", {
    "network": "ETH_MAINNET",
    "token_in": "USDC",
    "token_out": "NATIVE",
    "amount_in": "1000000000",
    "from_address": "0x1F33F99676B65968885adDFaFda3a736424d93C9",
    "quote_id": "0b6f8c7e-6a43-4d0a-9d7e-3c2f5a1e9b10",
})
for step in build["steps"]:
    print(step["index"], step["kind"], step["description"])
```

{% endtab %}

{% tab title="curl" %}

```bash
curl -s -X POST "https://swap-api.crypto-chief.com/$CC_API_KEY/v1/build" \
  -H "Content-Type: application/json" \
  -d '{"network":"ETH_MAINNET","token_in":"USDC","token_out":"NATIVE","amount_in":"1000000000","from_address":"0x1F33F99676B65968885adDFaFda3a736424d93C9","quote_id":"0b6f8c7e-6a43-4d0a-9d7e-3c2f5a1e9b10"}'
```

{% endtab %}
{% endtabs %}

### A build is a point in time

`amount_out_min` is computed from the state of this build. A long pause between steps, a moved price, a passed deadline — call `/v1/build` again with the same parameters rather than signing a stale step. The [Production Checklist](/guides/production-checklist.md) covers the full loop, including the retry rules for `429` and `503`.
