# Conversions (/reference/conversions)

## Your auto-conversion rule per network

`GET /v1/conversion/rules`

One entry per network enabled for your project: whether it can convert at all (and why not), whether you switched it on, the target coin, the coins you keep as received, and the target choices — stablecoins first, then every other coin listed on that network.

Conversion happens on chain, from the treasury, after a payment is credited and swept: a payment is never delayed or refused because of it, and a conversion that cannot be executed leaves the payment in the coin it arrived in.

### Responses

- `200` — Rules, one per enabled network.
  - `object` (required, string)
  - `data` (required, array)
  - `has_more` (required, boolean)
  - `next_cursor` (optional, string | null) — Opaque. Pass as `cursor` for the next page. Do not construct or parse it.
  - `data` (optional, array)
    - `object` (required, string)
    - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
    - `name` (optional, string)
    - `supported` (required, boolean) — Whether this network can auto-convert at all. `false` carries `unsupported_reason`; a PUT is refused with `conversion_unsupported_chain`.
    - `unsupported_reason` (optional, string | null)
    - `enabled` (required, boolean) — Off by default. Only the networks you switch on convert.
    - `target_asset` (required, string) — The coin every converted payment on this network becomes. Defaults to your settlement asset; must be one of `targets`.
    - `keep_assets` (required, array, of string) — Coins on this network left exactly as received. A payment in one of these is `skipped` with reason `kept`.
    - `swap_minimum_usd` (optional, string) — The smallest manual swap worth its gas, USD; the same on every network. A `POST /v1/conversions` or `POST /v1/own-wallet/swap` under it is refused 422 `below_minimum` — check the amount against it before asking.
    - `targets` (required, array) — What you may pick as the target, stablecoins first.
      - `symbol` (optional, string)
      - `stable` (optional, boolean)
      - `is_native` (optional, boolean)
      - `contract` (optional, string | null)
      - `logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
    - `updated_at` (optional, string | null (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — `merchant_not_found`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Switch auto conversion on a network on or off, and set its target and keep list

`PUT /v1/conversion/rules/{chain}`

Takes effect on the NEXT payment; rows already queued keep the target they were given. Refused with `conversion_unsupported_chain` on a network that cannot convert, `invalid_target` when the target is not listed on the network, and `invalid_keep_asset` when a keep entry is not.

### Parameters

- `chain` (path, required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)

### Request body (required)

- `enabled` (required, boolean)
- `target_asset` (required, string)
- `keep_assets` (optional, array, of string)

### Responses

- `200` — The rule as stored.
  - `object` (required, string)
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `name` (optional, string)
  - `supported` (required, boolean) — Whether this network can auto-convert at all. `false` carries `unsupported_reason`; a PUT is refused with `conversion_unsupported_chain`.
  - `unsupported_reason` (optional, string | null)
  - `enabled` (required, boolean) — Off by default. Only the networks you switch on convert.
  - `target_asset` (required, string) — The coin every converted payment on this network becomes. Defaults to your settlement asset; must be one of `targets`.
  - `keep_assets` (required, array, of string) — Coins on this network left exactly as received. A payment in one of these is `skipped` with reason `kept`.
  - `swap_minimum_usd` (optional, string) — The smallest manual swap worth its gas, USD; the same on every network. A `POST /v1/conversions` or `POST /v1/own-wallet/swap` under it is refused 422 `below_minimum` — check the amount against it before asking.
  - `targets` (required, array) — What you may pick as the target, stablecoins first.
    - `symbol` (optional, string)
    - `stable` (optional, boolean)
    - `is_native` (optional, boolean)
    - `contract` (optional, string | null)
    - `logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
  - `updated_at` (optional, string | null (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — `chain_not_found` or `merchant_not_found`.
- `422` — `conversion_unsupported_chain`, `invalid_target`, `invalid_keep_asset`, `too_many_keep_assets`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Every credited payment and what auto conversion did with it, plus your manual conversions

`GET /v1/conversions`

One row per payment, written when the payment is credited: `converted` with the executed rate and this payment's share of the swap's measured output, `skipped` with the reason (the rule was off, the coin is kept, it already was the target…), `queued` while it waits, or `failed` when every attempt reverted — which leaves the payment in the coin it arrived in. Manual conversions (`kind: manual`) appear here too, one row per customer balance they drew on.

### Parameters

- `limit` (query, optional, integer)
- `cursor` (query, optional, string) — Opaque cursor from the previous page's `next_cursor`.
- `status` (query, optional, string, one of: queued, converting, converted, skipped, failed)
- `chain` (query, optional, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
- `kind` (query, optional, string, one of: auto, manual)

### Responses

- `200` — Conversions, newest first.
  - `object` (required, string)
  - `data` (required, array)
  - `has_more` (required, boolean)
  - `next_cursor` (optional, string | null) — Opaque. Pass as `cursor` for the next page. Do not construct or parse it.
  - `data` (optional, array)
    - `object` (required, string)
    - `id` (required, string (uuid))
    - `ref` (required, string) — The MolnPay ID of this conversion — every row of one manual swap carries the swap's — `MOLN-` and twelve hex characters, shown on the receipt in the console and quoted to support. Stable for the life of the record; unlike `id`, safe to put in front of a person.
    - `kind` (required, string, one of: auto, manual) — `auto`: written when a payment was credited under a rule. `manual`: you asked for it (`POST /v1/conversions`).
    - `request_id` (optional, string | null (uuid)) — The manual request this row came from. One request writes one row per customer balance it drew on, and they share this id — `GET /v1/conversions/swaps` is the same rows grouped by it. Null on an auto row, and on manual rows made before requests were grouped.
    - `wallet` (required, string, one of: own, service) — Which pot the input came out of: `own` your own money, `service` what you hold for your customers. Auto conversions are always `service` — they follow payments.
    - `payment_id` (optional, string | null (uuid)) — The credited payment this row belongs to. One conversion per payment, ever. Null for a manual row.
    - `receipt_no` (optional, string | null)
    - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
    - `from_asset` (required, string) — The coin the payment arrived in.
    - `to_asset` (optional, string | null) — The target at the time of the payment. Null when no rule applied.
    - `from_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
    - `to_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
    - `amount_in` (required, string) — The payment's net credit, atomic units.
    - `amount_in_decimal` (optional, string)
    - `amount_out` (optional, string | null) — This payment's share of the batch's MEASURED output, atomic units. Null until converted.
    - `amount_out_decimal` (optional, string | null)
    - `rate` (optional, string | null) — Whole units of `to_asset` per whole unit of `from_asset`, as executed on chain.
    - `status` (required, string, one of: queued, converting, converted, skipped, failed) — `queued` waits for the treasury to hold the coin and for the group to clear the economics floor; `failed` means kept as received, never money lost.
    - `reason` (optional, string | null, one of: off, kept, already_target, chain_unsupported, test_mode, awaiting_sweep, below_minimum, gas_ratio, no_route, swap_failed, spent, null) — Why the row is not (or not yet) converted. Machine tokens.
    - `batch_id` (optional, string | null (uuid)) — The on-chain swap this row was executed in, with other payments of the same coin and target.
    - `tx_hash` (optional, string | null)
    - `explorer_url` (optional, string | null)
    - `attempts` (optional, integer)
    - `created_at` (required, string (date-time))
    - `updated_at` (optional, string (date-time))
    - `settled_at` (optional, string | null (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Convert part of your balance now

`POST /v1/conversions`

The same on-chain pipeline auto conversion uses, entered by hand: the amount is drawn from the customer balances that hold the coin, sized against what your treasury holds free of everything already in flight, and the swap is quoted and planned at once. Quote first with `POST /v1/conversions/quote`.

Refused with 402 `insufficient_funds` when the treasury on that network does not hold the amount (coins still in deposit addresses are swept first; `available` on the quote says what can go now), 422 `below_minimum` when the swap is worth less than `minimum_usd` on the quote (it would not be worth its gas), 422 `no_price` when the coin cannot be valued right now, 422 `billing_balance_exhausted` when the prepaid balance cannot carry the fees, 422 `conversion_unsupported_chain` on a network with no route, 422 `conversion_test_mode` on a test-mode project, 503 `conversion_unavailable` when conversion is not configured.

Returns 202 with the rows and, when it could be planned immediately, the batch. Follow the batch on `GET /v1/conversions/batches/{id}`; `conversion.completed` fires per row when it settles. Your plan's swap rate and the network gas, at cost, are charged from the prepaid balance on settlement — never out of the coins. A swap still queued can be withdrawn with `POST /v1/conversions/swaps/{id}/cancel`.

`Idempotency-Key` is REQUIRED: a retry with the same key replays the first answer rather than converting twice.

### Parameters

- `Idempotency-Key` (header, required, string) — REQUIRED. A retry without one can send funds twice, so the request is rejected outright.

### Request body (required)

- `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
- `from_asset` (required, string)
- `to_asset` (required, string)
- `amount` (required, string) — Atomic units of `from_asset`.

### Responses

- `202` — Accepted: the rows, and the batch when planned at once.
  - `object` (required, string)
  - `rows` (required, array) — The rows written for your request, one per customer balance the input was drawn from.
    - `object` (required, string)
    - `id` (required, string (uuid))
    - `ref` (required, string) — The MolnPay ID of this conversion — every row of one manual swap carries the swap's — `MOLN-` and twelve hex characters, shown on the receipt in the console and quoted to support. Stable for the life of the record; unlike `id`, safe to put in front of a person.
    - `kind` (required, string, one of: auto, manual) — `auto`: written when a payment was credited under a rule. `manual`: you asked for it (`POST /v1/conversions`).
    - `request_id` (optional, string | null (uuid)) — The manual request this row came from. One request writes one row per customer balance it drew on, and they share this id — `GET /v1/conversions/swaps` is the same rows grouped by it. Null on an auto row, and on manual rows made before requests were grouped.
    - `wallet` (required, string, one of: own, service) — Which pot the input came out of: `own` your own money, `service` what you hold for your customers. Auto conversions are always `service` — they follow payments.
    - `payment_id` (optional, string | null (uuid)) — The credited payment this row belongs to. One conversion per payment, ever. Null for a manual row.
    - `receipt_no` (optional, string | null)
    - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
    - `from_asset` (required, string) — The coin the payment arrived in.
    - `to_asset` (optional, string | null) — The target at the time of the payment. Null when no rule applied.
    - `from_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
    - `to_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
    - `amount_in` (required, string) — The payment's net credit, atomic units.
    - `amount_in_decimal` (optional, string)
    - `amount_out` (optional, string | null) — This payment's share of the batch's MEASURED output, atomic units. Null until converted.
    - `amount_out_decimal` (optional, string | null)
    - `rate` (optional, string | null) — Whole units of `to_asset` per whole unit of `from_asset`, as executed on chain.
    - `status` (required, string, one of: queued, converting, converted, skipped, failed) — `queued` waits for the treasury to hold the coin and for the group to clear the economics floor; `failed` means kept as received, never money lost.
    - `reason` (optional, string | null, one of: off, kept, already_target, chain_unsupported, test_mode, awaiting_sweep, below_minimum, gas_ratio, no_route, swap_failed, spent, null) — Why the row is not (or not yet) converted. Machine tokens.
    - `batch_id` (optional, string | null (uuid)) — The on-chain swap this row was executed in, with other payments of the same coin and target.
    - `tx_hash` (optional, string | null)
    - `explorer_url` (optional, string | null)
    - `attempts` (optional, integer)
    - `created_at` (required, string (date-time))
    - `updated_at` (optional, string (date-time))
    - `settled_at` (optional, string | null (date-time))
  - `batch` (required, object) — The swap, when it could be planned at once. Follow it on `GET /v1/conversions/batches/{id}`.
    - `object` (required, string)
    - `id` (required, string (uuid))
    - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
    - `from_asset` (required, string)
    - `to_asset` (required, string)
    - `amount_in` (required, string) — The batch's input, atomic units.
    - `amount_in_decimal` (optional, string)
    - `amount_out` (optional, string | null) — MEASURED from the receipt once confirmed. Null before.
    - `amount_out_decimal` (optional, string | null)
    - `expected_out` (optional, string | null)
    - `expected_out_decimal` (optional, string | null)
    - `min_out` (optional, string | null)
    - `rate` (optional, string | null) — As executed.
    - `amount_usd` (optional, string | null)
    - `fee_cents` (optional, integer)
    - `network_fee_cents` (optional, integer | null) — The gas the approve and the swap used, charged to the prepaid balance at cost when the batch settled (`conversion_network_fee`). Null until then, and when nothing was charged.
    - `network_fee_markup_cents` (optional, integer | null) — Our markup on that gas, charged beside it (`network_markup`, since 2026-09-28). Null whenever `network_fee_cents` is, and on a raw-cost account.
    - `market` (optional, string | null)
    - `status` (required, string, one of: approving, approved, swapping, landed, confirmed, failed) — `approving`/`approved`: the allowance transaction; `swapping`: the swap is planned or in flight; `landed`: confirmed, being measured; `confirmed`: settled; `failed`: the rows went back to the queue.
    - `error_code` (optional, string | null)
    - `approve_tx_hash` (optional, string | null)
    - `approve_explorer_url` (optional, string | null)
    - `swap_tx_hash` (optional, string | null)
    - `swap_explorer_url` (optional, string | null)
    - `rows` (required, integer) — How many conversion rows this batch carries.
    - `created_at` (required, string (date-time))
    - `updated_at` (optional, string (date-time))
    - `settled_at` (optional, string | null (date-time))
  - `pending_reason` (required, string | null) — When `batch` is null: why not yet (`no_route`, `gas_ratio`, `below_minimum`…). The rows stay queued and the planner retries.
- `401` — Missing, malformed, expired or revoked API key.
- `402` — `insufficient_funds`.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `422` — `below_minimum`, `no_price`, `billing_balance_exhausted`, `conversion_unsupported_chain`, `conversion_test_mode`, `unknown_asset`, `same_asset`, `invalid_amount`, `no_master_wallet`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — `conversion_unavailable` — conversion is not configured on this deployment.

## Withdraw a swap that is still queued

`POST /v1/conversions/swaps/{id}/cancel`

A swap is a promise until the planner claims it for a batch. Until then it can be taken back: every row still queued becomes `skipped` with reason `canceled`, and an own-wallet reserve is released in the same transaction, so the coins are available again at once.

Refused 409 `swap_not_cancelable` once a batch exists — the transaction is on its way, and it settles or fails on chain (a failure returns the coins by itself) — and after the swap has ended. `id` is the swap id `GET /v1/conversions/swaps` shows.

### Parameters

- `id` (path, required, string (uuid))

### Responses

- `200` — Canceled.
  - `object` (required, string)
  - `id` (required, string (uuid))
  - `rows_canceled` (required, integer) — How many of the swap's rows were still queued and are now `skipped`.
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — `swap_not_found`.
- `409` — `swap_not_cancelable` — already planned, or already over.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## The swaps you asked for, one row each

`GET /v1/conversions/swaps`

The same rows as `GET /v1/conversions?kind=manual`, grouped back into the thing you did. A swap of service-wallet money is written as one row per customer balance it drew on; here it is one swap, with the request's total in, what has been measured out, the executed rate, the fee, and both transactions.

Automatic conversions are never in this list — use `GET /v1/conversions` for everything together.

`status` is the underlying rows' status when they agree and `partial` when they do not, so it is filtered after the rollup; `chain` and `wallet` are the same for every row of a swap and filter before it.

### Parameters

- `limit` (query, optional, integer)
- `cursor` (query, optional, string) — Opaque cursor from the previous page's `next_cursor`.
- `status` (query, optional, string, one of: queued, converting, converted, skipped, failed, partial)
- `chain` (query, optional, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
- `wallet` (query, optional, string, one of: own, service)

### Responses

- `200` — Swaps, newest first.
  - `object` (required, string)
  - `data` (required, array)
  - `has_more` (required, boolean)
  - `next_cursor` (optional, string | null) — Opaque. Pass as `cursor` for the next page. Do not construct or parse it.
  - `data` (optional, array)
    - `object` (required, string)
    - `id` (required, string (uuid)) — The request id. Stable; it is what groups the underlying conversion rows.
    - `ref` (required, string) — The MolnPay ID of this swap — `MOLN-` and twelve hex characters, shown on the receipt in the console and quoted to support. Stable for the life of the record; unlike `id`, safe to put in front of a person.
    - `wallet` (required, string, one of: own, service) — `own` your own money, `service` what you hold for your customers.
    - `status` (required, string, one of: queued, converting, converted, skipped, failed, partial) — The underlying rows' status when they agree. `partial` when they do not — a swap spread across several customer balances can have some settled and some back in the queue. `failed` means the coins are exactly where they were.
    - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
    - `from_asset` (required, string)
    - `to_asset` (optional, string | null)
    - `from_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
    - `to_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
    - `amount_in` (required, string) — What you asked to swap, atomic units — the total across every row of the request.
    - `amount_in_decimal` (optional, string)
    - `amount_out` (optional, string | null) — What has been MEASURED on chain so far, atomic units. Null until a row settles; while `partial`, it is the part that has.
    - `amount_out_decimal` (optional, string | null)
    - `rate` (optional, string | null) — Whole units of `to_asset` per whole unit of `from_asset`, as executed.
    - `amount_usd` (optional, string | null) — Report-only, from the batch.
    - `fee_cents` (optional, integer | null) — What your plan charged for the batch that executed this swap. Null until it is planned.
    - `fee_shared` (optional, boolean) — True when that batch also carried rows this swap did not ask for, so `fee_cents` is the batch's and not this swap's alone. No pro-rata share is invented.
    - `network_fee_cents` (optional, integer | null) — The gas the approve and the swap actually used, charged to the prepaid balance at cost in USD when the batch settled (`conversion_network_fee`) — never out of the coins. Null until then, and null when nothing was charged. Shared under the same rule as `fee_cents`.
    - `network_fee_markup_cents` (optional, integer | null) — Our markup on that gas, charged beside it (`network_markup`, since 2026-09-28). Null whenever `network_fee_cents` is, and on a raw-cost account. Shared under the same rule as `fee_cents`.
    - `rows` (required, integer) — How many customer balances the input was drawn from. Always 1 for an own-wallet swap.
    - `rows_converted` (optional, integer) — How many of them have settled.
    - `reason` (optional, string | null) — Why it is waiting or was skipped, when the rows agree on one. Machine tokens, as on `Conversion`.
    - `attempts` (optional, integer)
    - `reserved` (optional, boolean) — The input is held aside until the swap settles — true for own-wallet swaps, which is what stops the same coins being withdrawn meanwhile.
    - `batch_id` (optional, string | null (uuid)) — The on-chain swap. Null before it is planned, and when a requeued swap is split across two.
    - `batch_status` (optional, string | null, one of: approving, approved, swapping, landed, confirmed, failed, null)
    - `market` (optional, string | null) — The route that was taken.
    - `approve_tx_hash` (optional, string | null) — A token input needs an allowance first; native inputs have none.
    - `approve_explorer_url` (optional, string | null)
    - `swap_tx_hash` (optional, string | null)
    - `swap_explorer_url` (optional, string | null)
    - `created_at` (required, string (date-time))
    - `updated_at` (optional, string (date-time))
    - `settled_at` (optional, string | null (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Price a manual conversion before committing

`POST /v1/conversions/quote`

Read-only. One route quote, the estimated gas, the fee your plan would charge, and how much of the coin your treasury can convert right now. Quotes are not held: the batch quotes again when it is planned, and the swap books what the chain actually delivers.

### Request body (required)

- `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
- `from_asset` (required, string)
- `to_asset` (required, string)
- `amount` (required, string)

### Responses

- `200` — The quote.
  - `object` (required, string)
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `from_asset` (required, string)
  - `to_asset` (required, string)
  - `amount_in` (required, string) — What you asked to convert, atomic units.
  - `amount_in_decimal` (optional, string)
  - `expected_out` (required, string) — What the route expects to deliver, atomic units. The swap books what actually arrives, never this.
  - `expected_out_decimal` (optional, string)
  - `min_out` (required, string) — The floor the router enforces; below it the swap reverts rather than fills.
  - `min_out_decimal` (optional, string)
  - `slippage_bps` (required, integer) — Basis points between expected and minimum.
  - `rate` (optional, string) — Whole units of `to_asset` per whole unit of `from_asset`, at the quote.
  - `amount_usd` (optional, string) — Report-only. `0.00` when no price is known.
  - `gas_usd` (optional, string) — Estimated gas for the approve (if any) and the swap. Paid on chain by the wallet that signs and charged to your prepaid balance at cost once the swap settles (`conversion_network_fee`) — never out of the coins.
  - `gas_markup_usd` (optional, string) — Our markup on that estimate, USD — `network_fee_markup_bps` of it, rounded up. Charged beside the real gas at settlement (`network_markup`). `0.00` on a raw-cost account.
  - `network_fee_markup_bps` (optional, integer) — The markup rate on the gas, bps. 0 on a raw-cost account and for the platform's own swaps.
  - `fee_cents` (optional, integer) — What your plan charges on settlement, from the operational balance.
  - `minimum_usd` (optional, string) — The smallest swap worth its gas, USD. A quote or request under it is refused 422 `below_minimum`.
  - `market` (optional, string) — The route Bitget would take.
  - `available` (required, string) — How much of `from_asset` your treasury can convert right now, net of everything already in flight.
  - `available_decimal` (optional, string)
  - `needs_approval` (optional, boolean) — A token input needs an approve transaction before the swap: two transactions, two confirmations.
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `422` — `below_minimum`, `no_price`, `billing_balance_exhausted`, `conversion_unsupported_chain`, `conversion_test_mode`, `unknown_asset`, `same_asset`, `invalid_amount`, `no_master_wallet`, `no_route`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — `conversion_unavailable` — conversion is not configured on this deployment.

## One on-chain swap, with its transactions

`GET /v1/conversions/batches/{id}`

### Parameters

- `id` (path, required, string (uuid))

### Responses

- `200` — The batch.
  - `object` (required, string)
  - `id` (required, string (uuid))
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `from_asset` (required, string)
  - `to_asset` (required, string)
  - `amount_in` (required, string) — The batch's input, atomic units.
  - `amount_in_decimal` (optional, string)
  - `amount_out` (optional, string | null) — MEASURED from the receipt once confirmed. Null before.
  - `amount_out_decimal` (optional, string | null)
  - `expected_out` (optional, string | null)
  - `expected_out_decimal` (optional, string | null)
  - `min_out` (optional, string | null)
  - `rate` (optional, string | null) — As executed.
  - `amount_usd` (optional, string | null)
  - `fee_cents` (optional, integer)
  - `network_fee_cents` (optional, integer | null) — The gas the approve and the swap used, charged to the prepaid balance at cost when the batch settled (`conversion_network_fee`). Null until then, and when nothing was charged.
  - `network_fee_markup_cents` (optional, integer | null) — Our markup on that gas, charged beside it (`network_markup`, since 2026-09-28). Null whenever `network_fee_cents` is, and on a raw-cost account.
  - `market` (optional, string | null)
  - `status` (required, string, one of: approving, approved, swapping, landed, confirmed, failed) — `approving`/`approved`: the allowance transaction; `swapping`: the swap is planned or in flight; `landed`: confirmed, being measured; `confirmed`: settled; `failed`: the rows went back to the queue.
  - `error_code` (optional, string | null)
  - `approve_tx_hash` (optional, string | null)
  - `approve_explorer_url` (optional, string | null)
  - `swap_tx_hash` (optional, string | null)
  - `swap_explorer_url` (optional, string | null)
  - `rows` (required, integer) — How many conversion rows this batch carries.
  - `created_at` (required, string (date-time))
  - `updated_at` (optional, string (date-time))
  - `settled_at` (optional, string | null (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — `conversion_batch_not_found`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## GET /v1/conversions/{id}

`GET /v1/conversions/{id}`

### Parameters

- `id` (path, required, string (uuid))

### Responses

- `200` — The conversion.
  - `object` (required, string)
  - `id` (required, string (uuid))
  - `ref` (required, string) — The MolnPay ID of this conversion — every row of one manual swap carries the swap's — `MOLN-` and twelve hex characters, shown on the receipt in the console and quoted to support. Stable for the life of the record; unlike `id`, safe to put in front of a person.
  - `kind` (required, string, one of: auto, manual) — `auto`: written when a payment was credited under a rule. `manual`: you asked for it (`POST /v1/conversions`).
  - `request_id` (optional, string | null (uuid)) — The manual request this row came from. One request writes one row per customer balance it drew on, and they share this id — `GET /v1/conversions/swaps` is the same rows grouped by it. Null on an auto row, and on manual rows made before requests were grouped.
  - `wallet` (required, string, one of: own, service) — Which pot the input came out of: `own` your own money, `service` what you hold for your customers. Auto conversions are always `service` — they follow payments.
  - `payment_id` (optional, string | null (uuid)) — The credited payment this row belongs to. One conversion per payment, ever. Null for a manual row.
  - `receipt_no` (optional, string | null)
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `from_asset` (required, string) — The coin the payment arrived in.
  - `to_asset` (optional, string | null) — The target at the time of the payment. Null when no rule applied.
  - `from_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
  - `to_asset_logo_url` (optional, string | null) — Decoration; see `Asset.logo_url`.
  - `amount_in` (required, string) — The payment's net credit, atomic units.
  - `amount_in_decimal` (optional, string)
  - `amount_out` (optional, string | null) — This payment's share of the batch's MEASURED output, atomic units. Null until converted.
  - `amount_out_decimal` (optional, string | null)
  - `rate` (optional, string | null) — Whole units of `to_asset` per whole unit of `from_asset`, as executed on chain.
  - `status` (required, string, one of: queued, converting, converted, skipped, failed) — `queued` waits for the treasury to hold the coin and for the group to clear the economics floor; `failed` means kept as received, never money lost.
  - `reason` (optional, string | null, one of: off, kept, already_target, chain_unsupported, test_mode, awaiting_sweep, below_minimum, gas_ratio, no_route, swap_failed, spent, null) — Why the row is not (or not yet) converted. Machine tokens.
  - `batch_id` (optional, string | null (uuid)) — The on-chain swap this row was executed in, with other payments of the same coin and target.
  - `tx_hash` (optional, string | null)
  - `explorer_url` (optional, string | null)
  - `attempts` (optional, integer)
  - `created_at` (required, string (date-time))
  - `updated_at` (optional, string (date-time))
  - `settled_at` (optional, string | null (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — `conversion_not_found`.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.