Rates & Pricing
How quoting works: rate semantics, quote lifetimes, and the recommended create-order flow. The endpoint reference lives at Rates; this page explains the model.
Pair naming and rate direction
A pair name is {to}{from} — the receive currency first, then the send currency. BTCUSDC means "you send USDC, you receive BTC". Every rate row spells the direction out explicitly:
from— what you send (deposit currency)to— what you receive (withdraw currency)
rate is quoted as deposit units per 1 receive unit (the marked-up ask). It does not include fixed fees. The amount you receive is therefore:
withdraw_amount = deposit_amount / rate − withdrawal_fee
where withdrawal_fee is the combined fixed fees expressed in the receive (to) currency.
Instead of applying the formula client-side, pass deposit_amount to GET /rate/ with exactly one pair — the response then includes a withdraw_amount preview computed through the same pricing path used at order creation. That is the exact number to show the user.
Pricing modes
| Mode | Request | rate_id | expiration_time_unix | Behavior |
|---|---|---|---|---|
| CeFi fixed (default) | is_fixed_rate=true or omit | present | present | Quote snapshot stored; pass rate_id at order creation to bind validation to it |
| CeFi floating | is_floating_rate=true | absent | absent | No price lock; the order executes at the live rate at creation time |
| DeFi floating | is_defi=true | present | present | Indicative pricing; amount determined at execution |
| DeFi fixed | is_defi=true&is_fixed_rate=true | present | present | The row's rate is what the order promises; see DeFi fixed-rate quotes below |
| DeFi limit | order-level is_limit_order | n/a | n/a | No quote at all — you set limit_receive_amount; see Orders |
is_fixed_rate and is_floating_rate are mutually exclusive. is_floating_rate is CeFi-only and ignored for DeFi.
DeFi fixed-rate quotes
Every DeFi fixed-rate row is bindable: the rate you display is the rate the order promises. The flow has three steps:
GET /rate/?is_defi=true&is_fixed_rate=true(filtered to the pairs you show) to display prices.- When the user picks a pair and amount, fetch that pair again for a fresh
rate_id. Passingdeposit_amountdoes not change a DeFi rate. POST /orders/with the same deposit amount and thatrate_id.
At order creation the venue is quoted for the exact deposit. The order promises deposit / rate (minus the network fee on Ethereum-source orders, shown as withdrawal_fee), and that promise is what gets delivered. If the venue cannot reach it, creation either proceeds with a slightly lower amount (within a small tolerance) or fails with The market has moved beyond this rate's tolerance. Please request a new rate. In both cases, show the user the amount from the order creation response, not a client-side estimate.
curl -X GET "https://api.n.exchange/en/api/v2/rate/?pairs=USDCARBETHARB&is_defi=true&is_fixed_rate=true" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "x-referral-token: YOUR_REFERRAL_TOKEN"
actionable_quote removedThe actionable_quote parameter no longer exists. It is ignored if sent, so existing integrations keep working and receive the same bindable row as everyone else.
Quote lifetime: rate_id and expiration_time_unix
rate_ididentifies a stored quote snapshot for that specific row (pair + mode). It is not transferable across pairs or modes.expiration_time_unixis a string containing a unix timestamp in seconds. Parse it as an integer.- Quote TTLs are short — typically tens of seconds. Under fast-moving markets a returned quote may already be at or past its expiry when it reaches you. Always compare
expiration_time_unixagainst your own clock at the moment of use, not receipt, and treat non-future expiries as "refresh before use".
Recommended create-order flow (refresh on submit)
- Display prices from a recent
GET /rate/read. - On user submit, fetch a fresh quote for the exact pair and amount.
- Create the order with that row's
rate_id. - If creation fails with a rate-expired validation error, fetch one more fresh quote, compare the new
withdraw_amountagainst what the user accepted, and either retry once with the newrate_idor surface a "price moved" confirmation to the user.
Passing rate_id binds order validation to the quote snapshot. Omitting it means the order is priced at creation time with no reference to what you displayed.
Binding a rate_id validates the order against the quote snapshot at creation, but the finally confirmed withdraw_amount can still differ on volatile pairs (e.g. DeFi execution slippage within allowed bounds). If your UX promises a minimum received amount, verify the created order's amounts in the response and reconcile on completion — or use a DeFi limit order, which enforces a minimum receive amount by construction.
Always filter your rate requests
GET /rate/ without a pairs filter (or currency parameters) returns the entire catalogue — thousands of rows and a response measured in megabytes, with correspondingly slow generation. Production integrations should always request specific pairs:
# Good — bounded and fast
GET /rate/?pairs=BTCETH,ETHBTC
# Avoid in production — full catalogue scan
GET /rate/
If you need the full pair universe, fetch GET /pair/ (names only, cheap) and request rates for the pairs you actually display.
Pair availability is dynamic
The set of quotable pairs changes with liquidity and can be direction-asymmetric — ETHARBUSDCARB may be quotable while USDCARBETHARB is not. A pair present in GET /pair/ may still have no rate row right now. Treat "no row returned for the requested pair" / 404 No trading pairs found as pair temporarily unavailable, not as an integration error, and re-check later rather than caching the absence.
ETA
Pass include_eta=true to add eta_seconds to each row — the estimated swap completion time (median of recent orders on the same network pair for CeFi; a fixed estimate for DeFi). null means no estimate is available. Off by default.
Fees and partner markup
withdrawal_fee— combined fixed fees in the receive currency (see formula above).markup— dynamic partner fee in basis points (integer,50= 0.5%). Preferred spelling; requires the capability to be pre-enabled on your referral code.referral_rate— deprecated decimal-fraction spelling of the same thing ("0.005"). Sending bothmarkupandreferral_ratereturns400.applied_referral_rate— in rate rows and order responses: the fee actually applied after any partner cap (excess above the cap is split 50-50). Only present when a dynamic fee was requested.
Next steps
- Rates reference — full parameter table
- Orders — creating orders with
rate_id - Errors & Rate Limits — rate-expiry error handling