0Bit Documentation

Create a 0Pools quote

POST /pools/{id}/quote - Lock a short-lived quote for an entitled pool, including the on-ramp delivery address contract.

0Pools API pages are for approved headless partners. They cover the partner-visible quote, transact, status, trade, and balance lifecycle only.

Pricing a conversion and locking a quote is the first money-shaped step in the lifecycle. A quote captures the side, the pair, the amount, the partner-visible economics, and — for a buy — the delivery address. Your server reads the quote, shows the user only the partner-visible economics, and either executes once before expiry or lets the quote lapse.

Endpoint

FieldValue
MethodPOST
Path/v1/pools/{id}/quote
AreaQuotes
Operation idcreateQuote
Auth boundarySecret key from your server.

The {id} path parameter is a pool id this partner is entitled to, discovered from GET /pools. A pool id you are not entitled to returns 404 (cross-tenant access is never 403).

Use it for

Price a specific conversion and lock a short-lived, single-use quote for an entitled pool. For a buy (on_ramp), the call also captures and locks the on-chain delivery address that the purchased crypto will be sent to at settlement.

Use this endpoint only for the partner-scoped resource it describes. Store your own reference id, the returned quoteId, the request id, timestamps, and the current status so support and reconciliation do not depend on browser callbacks alone.

Production rules

  • Keep secret keys on your server. This endpoint requires a sk_* key.
  • Validate environment, mode, entitlement, asset, network, and amount before the call.
  • For a buy, validate the delivery address before requesting the quote — it is locked at this step and cannot be changed later.
  • Branch on machine-readable status, error code, object id, and request id.
  • Treat examples and placeholder ids as fake data only.

Request body

FieldRequiredTypeUse it for
sideYeson_ramp/off_rampDirection of the conversion. See Sides and the amount role.
fiatCurrencyYesstring (ISO 4217)Three-letter fiat code, for example EUR.
cryptoCurrencyYesstringCrypto asset symbol, for example USDT.
amountYesdecimal stringPositive amount. Its unit depends on side — see below. Always a string, never a float.
cryptoNetworkNo (default tron)tron/ethereum/bsc/polygon/solanaThe chain the trade transacts on; selects the pool and deposit address. Locked on the quote and never read from the transact body. Distinct from destNetwork.
typeNo (default firm)firm/indicativeWhether to lock an executable quote or only return a price. See Firm vs indicative.
destAddressRequired for an on_ramp buy (crypto delivery)string (EVM 0x…)Wallet address the purchased crypto is delivered to. Validated and locked on the quote. See On-ramp delivery.
destNetworkNostringEVM delivery network for destAddress. Defaults to the quoted cryptoNetwork when omitted. See On-ramp delivery.

Money and rate values are strings

Every monetary and rate value in 0Pools is a decimal string, never a float. Basis-point fields are integers.

Sides and the amount role

side sets the direction of the conversion and therefore what amount means.

sideMeaningamount is…The response describes…
on_rampBuy crypto with fiat (fiat → crypto)the fiat you pay inthe crypto the user receives.
off_rampSell crypto for fiat (crypto → fiat)the crypto you sellthe fiat the user receives.

rate is always expressed as output per unit of input for the chosen side, as a decimal string.

off_ramp is gated

Selling is not publicly enabled by default. A POST /pools/{id}/transact for an off_ramp quote deny-closes with 501 until your account is enabled for it, and even then requires a crypto-receipt step first. You can still request off_ramp quotes, but plan the flow around the gate. See Execute against a quote.

Firm vs indicative

type controls whether the call locks an executable quote or just returns a price.

typePersisted?Returns quoteId?executableUse it for
firm (default)YesYestrueA real, single-use lock you can pass to transact before it expires.
indicativeNoNofalseA price-only preview for display or planning. It cannot be transacted.

A firm quote returns a quoteId and an expiresAt roughly 15 seconds in the future. It is single-use: once you transact it (or reject it, or it expires) it cannot be reused. Show the user only the partner-visible economics and execute once before expiresAt.

An indicative quote returns available: true with executable: false and no quoteId and no expiresAt. It is never persisted and can never be passed to transact. Use it to render a price without committing inventory.

Only act on executable: true. Never attempt to transact an indicative quote, and never transact a quote that is reported unavailable.

On-ramp delivery contract

For a buy (on_ramp), destAddress is required and is captured and locked onto the quote at this step.

  • It is validated as an EVM 0x… (40-hex) address against an EVM-only allowlist. The EIP-55 checksum is enforced only for mixed-case addresses; an all-lowercase or all-uppercase address passes on format.
  • destNetwork, when provided, must be one of the allowed EVM networks; when omitted it defaults to the quoted cryptoNetwork.
  • At transact, the locked delivery target is copied onto the trade from the quote, never from the transact body — there is no way to redirect delivery after the quote is locked.
  • The crypto is delivered to that address when the trade settles.
  • A missing destAddress on an on_ramp quote is a 400.

Delivery networks are EVM-only:

NetworkCommon token standard
Arbitrum(e.g. USDT on Arbitrum)
EthereumERC-20
BSCBEP-20
Optimism(EVM)
Polygon(EVM)

The customer only needs an EVM wallet address

Because delivery is EVM-only, the end customer needs nothing more than a single EVM wallet address — no wallet on any other chain. Read GET /pools/{id}/capabilities for the exact supportedNetworks instead of hard-coding them.

Response

The response is always HTTP 200 — both an available quote and an unavailable pool return 200. Branch on the available flag, not on the status code.

FieldWhen presentUse it for
availableAlwaystrue for a locked or priced quote; false when the pool cannot be quoted.
typeWhen available: trueEchoes firm or indicative.
executableWhen available: truetrue only for a firm quote that can be passed to transact.
quoteIdFirm quotes onlyJoin quote, trade, status, and reconciliation records; pass to transact.
rateWhen available: truePartner-visible all-in rate (output per input), as a decimal string.
spreadBpsWhen available: truePool FX spread baked into the rate, in basis points (capped at 50).
feeBpsWhen available: trueYour tier draw fee baked into the rate, in basis points (not capped).
minOrderUsdtWhen available: trueMinimum order size for this pool, in USDT (number).
maxOrderUsdtWhen available: trueMaximum order size for this pool, in USDT (number), or null when there is no cap.
expiresAtFirm quotes onlyQuote expiry (~15s out). Prevent stale accept buttons.
unavailableReasonWhen available: falseSafe machine-readable reason. No quoteId is issued.

For per-pool spread and fee ceilings and order limits, read GET /pools/{id}/capabilities rather than hard-coding values.

Unavailable (fail-soft) response

When the route cannot be priced, the API returns 200 with available: false, an unavailableReason, and no quoteId. This is a normal outcome, not an error — never treat it as a failure to retry in a tight loop, and never attempt to transact it.

unavailableReasonMeaning
pool_dryThe pool has no available depth for this conversion right now.
engine_unavailablePricing is temporarily unavailable.
rate_unavailableNo current rate could be sourced for the pair.

Show the user a partner-visible unavailable state, optionally offer another pool, and back off before re-quoting.

Examples

curl -X POST https://pools-api.0bit.app/v1/pools/pool_test_123/quote \
  -H "Authorization: Bearer sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "side": "on_ramp",
    "fiatCurrency": "EUR",
    "cryptoCurrency": "USDT",
    "amount": "100.00",
    "cryptoNetwork": "tron",
    "type": "firm",
    "destAddress": "0x52908400098527886E0F7030069857D2E4169EE7",
    "destNetwork": "arbitrum"
  }'
{
  "available": true,
  "type": "firm",
  "executable": true,
  "quoteId": "pq_test_8f3c000000000123",
  "rate": "1.0731",
  "spreadBps": 25,
  "feeBps": 30,
  "minOrderUsdt": 10,
  "maxOrderUsdt": 50000,
  "expiresAt": "2026-01-01T00:00:15Z"
}

A firm quote is single-use. Store the quoteId and expiresAt, then call POST /pools/{id}/transact once before it expires.

{
  "available": true,
  "type": "indicative",
  "executable": false,
  "rate": "1.0731",
  "spreadBps": 25,
  "feeBps": 30,
  "minOrderUsdt": 10,
  "maxOrderUsdt": 50000
}

Price-only. There is no quoteId and no expiresAt; it cannot be transacted. Re-request a firm quote when the user is ready to commit.

{
  "available": false,
  "unavailableReason": "pool_dry"
}

HTTP 200. No quoteId is issued. Show an unavailable state and back off; never transact this response.

Errors

All errors use the unified envelope and carry an X-Request-Id response header. Branch on code/type/statusCode, not on the free-form message.

{
  "type": "invalid_request",
  "code": "invalid_request",
  "message": "Example validation error using fake data.",
  "request_id": "req_test_000000000123",
  "doc_url": null,
  "statusCode": 400
}
StatustypeWhen it happens
400invalid_requestBad body — missing destAddress on an on_ramp, a non-checksummed/invalid EVM address, a destNetwork not on the allowlist, a bad amount, or an unknown currency/asset.
401unauthorizedMissing or invalid secret key.
403forbiddenAccess denied. Branch on code: pools_not_enabled, pool_access_suspended, kyc_not_approved, pool_not_allowed, key_mode_mismatch.
404not_foundPool not found or not entitled to this partner. Cross-tenant access is 404, never 403.
429rate_limitedRequest throttled. Back off and retry.
5xxserver_errorTransient server or upstream failure. Retry with bounded backoff.

Unavailable is not an error

A dry or temporarily unquotable pool returns 200 with available: false — not a 4xx/5xx. Reserve error handling for the statuses above.

Public boundary

This reference covers partner-visible discovery, quote, transact, status, trade, and balance behavior. Liquidity operations, routing internals, settlement venues and networks, provider details, reserve logic, and runbooks are outside the public API contract.

On this page