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 (RFQ) | is_defi=true&is_fixed_rate=true | present | present | Request-for-quote pricing; see actionable vs indicative 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.
Indicative vs actionable quotes (DeFi fixed-rate)
DeFi fixed-rate rows are indicative by default — a price you can display, not one the system has committed to. To get an actionable quote (one an order can actually bind to), the request must satisfy all three conditions:
- exactly one pair requested,
deposit_amountprovided,actionable_quote=true.
curl -X GET "https://api.n.exchange/en/api/v2/rate/?pairs=USDCARBETHARB&is_defi=true&is_fixed_rate=true&deposit_amount=10&actionable_quote=true" \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "x-referral-token: YOUR_REFERRAL_TOKEN"
Multi-pair or amountless fixed-rate requests always return indicative rows, even for same-chain pairs.
Actionable fixed-rate quoting is an on-demand request-for-quote against live liquidity and can take noticeably longer than indicative reads — occasionally 10 seconds or more. Set client timeouts accordingly (15s or higher is recommended) and fall back to indicative display pricing if the quote does not arrive in time.
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