Skip to navigation

Reference data guide

How the reference data endpoints page, filter and sort, spell symbols, report freshness and answer errors

The conventions every resource follows. The reference documents each resource; this page covers what they have in common.

Authentication

Every request carries a bearer token: Authorization: Bearer <token>. A missing, expired or foreign token is 401 UNAUTHENTICATED, with a WWW-Authenticate header naming the problem.

Values

  • Ids are opaque strings, named after their entity: venueId, instrumentId. An id that does not exist is 404 NOT_FOUND, whatever its shape.
  • Numbers — prices, quantities, amounts — are exact decimal strings such as "0.0000001115". Parse them as decimals, never as floating point. The number of digits carries no meaning.
  • Times are epoch-nanosecond strings named …AtNs or …TsNs.
  • Absent values are always present, as null.
  • Enums are UPPER_SNAKE and only ever grow. Tolerate values you don’t know.

Lists

Every collection returns one page at a time:

{
"items": [],
"nextCursor": null,
"prevCursor": null,
"total": null,
"asOfSeqTsNs": "1758640000123456789"
}
  • limit sets the page size: 1 to 100, default 50. Larger values are reduced to 100, never refused.
  • To move, send nextCursor or prevCursor back as cursor, with the same filters and sort. A cursor is bound to the query it came from.
  • A cursor the API cannot use — edited, expired by a key rotation, or sent with a different query — is 400 INVALID_CURSOR. Drop it and fetch the first page again.
  • sort takes comma-separated properties; a leading - sorts descending. The order is always complete: ties are broken by the id, and absent values sort last, in both directions. On instruments, a statistic is absent for an instrument that has never traded, a 24-hour one while its window is still warming, and any the projection cannot state, such as a turnover it has no price to value.
  • include opts into extras, comma-separated. Every collection offers total, the exact count of matching items (null otherwise). Instruments also offer facets (counts per venue, type, base asset and quote asset, each counted under your filters minus that dimension’s own, so a filter panel keeps showing its alternatives) and ticker (each row’s latest statistics).
  • Filters are plain query parameters. Repeat a parameter, comma-separate its values, or both, for “any of”: venueId=300&venueId=301 is venueId=300,301. Different parameters narrow together: type=SPOT&venueId=300 is the spot markets of venue 300. A parameter the resource does not accept is 400 MALFORMED_REQUEST, so a misspelt filter never silently returns the unfiltered list. A filter value that matches nothing is an empty page: an unknown code or symbol, or an id that is not exactly one. A filter that takes an alias in place of an id (venue=okx, baseAsset=BTC) ignores case. An enum filter refuses a value it has never heard of (type=CRYPTO) with 400 MALFORMED_REQUEST. It accepts every documented value and every value its rows carry, removed rows included, so a value you were served stays valid: enums only grow.
  • The .notIn suffix excludes instead: venueId.notIn=10 matches every venue but that one. Where a resource offers ranges it documents .gte and .lte the same way.
  • search is case-insensitive and resource-specific. Instruments match word prefixes of the symbol’s tokens, the venue’s own symbol, the type and the id: btc usdt finds OKX@BTC/USDT:USDT, perp finds every perpetual swap. Venues match a substring of the code or display name; assets match a substring of the symbol.

Symbols

Every instrument has one canonical symbol, byte-identical to the symbol on the market-data stream, in the grammar VENUE@BASE/QUOTE[:SETTLE[-DDMmmYY[-STRIKE-C|P]]]:

ShapeExample
SpotOKX@BTC/USDT
Perpetual swapOKX@BTC/USDT:USDT (linear), OKX@BTC/USD:BTC (inverse)
Dated futureBYBIT@BTC/USDT:USDT-25Jun27
OptionBYBIT@BTC/USDC:USDC-26Sep26-100000-C (a call; -P is a put)

VENUE is the venue code upper-cased; SETTLE is the asset the contract settles in; the date is the day, the month’s three-letter name and a two-digit year; STRIKE is the strike price. A lookup by symbol is case-insensitive; the symbol served always uses this spelling.

GET /instruments?symbol=OKX@BTC/USDT&symbol=okx@btc/usdt:usdt-25JUN27 looks up to 100 symbols in one request; send limit=100 to get a whole batch in one page. A symbol that names no instrument is simply absent from the page. More than 100 is 400 MALFORMED_REQUEST, a symbol sent twice counting twice: split a longer list into batches. The request line and headers may run to 16 KB, room for a batch of the longest symbols and a bearer token.

A dated product’s maturity is DDMmmYY and nothing else. A name stored with the older YYYYMMDD maturity, such as OKX@BTC/USDT:USDT-20270625 for OKX@BTC/USDT:USDT-25Jun27, finds nothing: convert it before looking it up.

Freshness

Reads carry the position of the event stream they reflect: the X-Immix-As-Of-Seq-Ts header, and asOfSeqTsNs in list pages. It is a sequencer timestamp in epoch nanoseconds, the same clock as seqTs on stream frames: every stream message at or before it is reflected in the response, so you can apply stream updates after it without gaps or repeats. A response built from several sources reports the oldest: an instruments page, which joins the catalogue with the latest statistics, reports the older of the two. When the position is unknown, the header is omitted and asOfSeqTsNs is null.

Errors

Every error uses one envelope:

{
"error": {
"code": "INVALID_CURSOR",
"message": "The cursor is not valid for this request; drop it and fetch the first page again.",
"retryable": false,
"requestId": "5f0c6c1e-8a2b-4f7e-9c3d-2b1a0e9f8d7c"
}
}

Branch on code, never on message. retryable says whether the same request may succeed later. Quote requestId (also the X-Request-Id header) when you contact support.

CodeStatusMeaning
MALFORMED_REQUEST400A parameter is unknown, repeated or out of range
INVALID_CURSOR400The cursor cannot be used with this request
UNAUTHENTICATED401The bearer token is missing or not valid
NOT_FOUND404No such resource
METHOD_NOT_ALLOWED405The resource does not support this method
NOT_ACCEPTABLE406Responses are application/json
RATE_LIMITED429Slow down; Retry-After says when
INTERNAL_ERROR500Something went wrong on our side
NOT_IMPLEMENTED501The operation is published but not served yet
PROJECTION_UNAVAILABLE503Reference data is briefly unavailable; retry

Codes are append-only: new ones will appear, and existing ones never change meaning.