Data Types & Conventions
Decimal strings
All prices, sizes, and spreads are returned as strings, never floats. This preserves decimal precision that would be lost in JSON number parsing.
{
"target_size": "2.5",
"target_spread": "0.01",
"filled_size": "1.25"
}Use a decimal library client-side, e.g.:
- Python:
decimal.Decimal - JavaScript:
bignumber.js,big.js, ordecimal.js - Go:
shopspring/decimal
Do not parse decimal strings as float64 / Number. You'll lose precision
on values like 0.1 + 0.2.
Timestamps
All timestamps are RFC 3339 in UTC:
"2026-03-12T13:06:58Z"The Z suffix is always present (never an offset like +00:00 or -05:00).
Time zones in your local UI are your problem; the API speaks UTC.
Wallet addresses
Ethereum-style hex, always lowercase, with 0x prefix:
"0xYourWalletAddressHere"The API normalizes mixed-case input to lowercase on storage. Your queries should also use lowercase to avoid mismatches.
Exchange identifiers
Lowercase, exactly as listed:
| Identifier | Exchange |
|---|---|
hyperliquid | Hyperliquid |
extended | Extended (x10) |
lighter | Lighter (zkLighter) |
lighter_rh | Lighter [RH] (Lighter on Robinhood Chain) |
orderly | Orderly Network |
aster | Aster (asterdex) |
grvt | GRVT |
apex | ApeX Omni |
hl_xyz | trade[xyz] (Hyperliquid builder DEX) |
nado | Nado (maker leg only) |
The API only format-checks exchange names (alphanumeric/underscore) at submission time; an unrecognized exchange fails slightly later with a credential-lookup error ("no active credentials for wallet ... on ..."), not a dedicated validation error.
Market symbols
The market field in trade creation uses canonical symbols (e.g. BTC,
ETH, HYPE, SOL). Spreadr translates these into the venue-specific
symbols at execution time.
Get the full list of available canonical symbols + per-exchange mappings from Available Markets.
UUIDs
trade_id is a v4 UUID, 36 characters including hyphens:
"00000000-0000-0000-0000-000000000000"User-supplied idempotency keys must match ^[a-zA-Z0-9_-]{1,128}$ —
alphanumeric, hyphen, underscore only (a UUID works).
Enum values
All enums are lowercase strings:
spread_condition—gte,gt,lte,lt,eqmaker_leg—long,shortsize_type—base,notionalspread_type—absolute(raw USD price difference),percentage(% of hedge reference price),bps(basis points of hedge reference price),ticks(multiples of the coarser leg's tick size)execution_type— currently onlymaker_taker- Trade status —
pending,validating,active,paused,recovering,completed,canceled,rejected,failed
Failure codes
Terminal trades (completed, canceled, failed, rejected) carry
failure_code and failure_detail next to the free-text failure_reason.
The code is derived at read time from status + failure_reason, so trades
that closed before it existed carry one too. Match on the code, not on the
text.
failure_code | Status | Meaning |
|---|---|---|
completed | completed | Target size fully filled |
canceled_clean | canceled | No fill was open at cancel time |
canceled_with_fills_hedged | canceled | Fills existed and a hedge-venue corrective left the legs balanced (the residual was hedged, or an over-hedge was reduced) |
canceled_with_fills_completed | canceled | Fills existed; the maker leg was completed at market to match a pre-hedge |
canceled_with_fills_flattened | canceled | Fills existed; the residual was closed reduce-only on the maker venue |
canceled_exposure_remains | canceled | A corrective failed, or on_cancel_fill: "report" left the residual in place. Read net_exposure and failure_detail; the position needs attention |
canceled_kill_switch | canceled | Halted by the user or global kill switch (also killed_by_switch: true) |
canceled_other | canceled | Canceled with a reason not enumerated above |
hedge_rejected | failed | The hedge venue refused the hedge deterministically (no retry can succeed). The residual was flattened where possible — check net_exposure |
hedge_failed_flattened | failed | The hedge failed after all retries and the residual was flattened |
hedge_failed_exposure_remains | failed | The hedge failed after all retries and the flatten failed too |
hedge_abandoned | failed | The hedge budget was exhausted and the residual abandoned |
recovery_exhausted | failed | The worker was repeatedly terminated during recovery |
liquidation | failed | A leg was liquidated |
maintenance | rejected | System or venue maintenance |
market_not_tradeable | rejected | Market unknown or not tradeable on a venue |
no_leverage | rejected | No user leverage available on a venue |
below_min_size | rejected | Target size or notional below the venue minimum |
negative_available_balance | failed | Refused before anything rested: a leg closes a position on a venue whose available balance is negative, and such closes are refused. Not on Hyperliquid or GRVT, which admit closes at any balance; and not for the hedge leg of a reduce_only trade on Extended, whose reduce-only orders Extended admits at any balance. Add collateral or raise leverage on that venue, or send the close as reduce_only with the Extended leg as the hedge, then retry |
insufficient_margin | failed | Refused before anything rested: a venue's available balance is below what the leg needs |
reduce_only_would_open | failed | A reduce_only leg holds no opposing position, or a smaller one than the size — it would open exposure, so the trade was refused before anything rested |
reduce_only_unverified | failed | A reduce_only trade whose positions could not be read to verify the close (after retries). Transient — retry |
hl_address_budget_exhausted | failed | Hyperliquid refused the wallet's address, not the order: its cumulative request budget (10,000 + 1 per USDC traded) is used up, and until volume raises it HL admits one request per 10 s. The trade fails on the first such rejection of a placement instead of retrying; failure_detail carries the requests used and the cap. A refused re-price does not fail the trade: the maker holds its resting order until the address has headroom again (an hl_address_budget_hold event). A hedge rejected this way also fails on the first rejection, reported as hedge_rejected with Hyperliquid's message in failure_detail |
hl_action_budget_exhausted | failed | An entry spent its own per-trade Hyperliquid action cap (hl_action_budget; by default the trade's USD notional, at least 100). Its maker would have re-priced again, so the order was cancelled and the trade ended with what had filled, hedged; a no-fill when nothing had filled. failure_detail carries the actions used and the cap. A reduce_only close that runs out is finished at market instead and completes. See Hyperliquid action cap |
credential_invalid | failed | The venue says the trading key Spreadr holds for it is expired, deleted or replaced (a Hyperliquid or Orderly key past its expiry, a revoked or overwritten API key). Refused before anything rested, or a placement the venue refused for the key; no retry can succeed. failure_detail names the venue and what to reconnect (Settings → Wallets) |
failed_other / rejected_other | failed / rejected | Terminal with a reason not enumerated above |
Codes are additive: a new code may appear in /api/v1 without a version
bump, so treat an unknown value as "terminal, inspect failure_detail".
Pagination
The current API does not paginate. List endpoints return the most recent 50
items unconditionally. If/when pagination is added, it'll use cursor-based
parameters (since, limit) — not page numbers.
Versioning
Everything is under /api/v1. Breaking changes will go under /api/v2;
non-breaking additions (new optional fields, new endpoints) will land in
/api/v1 without a version bump.