Getting started

Responses and errors

Every response has the same shape. This page describes the envelope, the way to reduce its size, how to read an empty field, and what each error code means.

#The standard envelope

Response
{
  "status": "ok",
  "timestamp": 1775648290510,
  "data_type": "basis",
  "data": {
    "basis_value": 42.18,
    "basis_pct": 0.059,
    "futures_price": 71462.51,
    "spot_price": 71420.33,
    "timestamp": "2026-08-29T11:38:00+00:00"
  }
}
FieldTypeDescription
statusstringok or error.
timestampintegerThe instant the response was produced, in milliseconds since the Unix epoch. Never the timestamp of the data.
data_typestringThe name of the type returned. It lets you route a response without relying on the path called, which is useful when a client goes through a queue or a cache.
dataobject | array | nullThe payload. null when the metric has nothing to serve over the window asked for.

Two exceptions to know about

Three routes do not go through this envelope and serve their own shape: /v1/health, /v1/status and POST /v1/indicators, which builds its response itself. The first two are probes, the third carries an indicators object indexed by your identifiers.

#Reducing the response

The ?fields= parameter restricts data to the fields asked for: a comma-separated list, in dotted notation for nested fields. On a series of a thousand rows where you only use two columns, the response shrinks as much.

curl
# The full response
curl -H "X-API-KEY: $BYTNODE_KEY" \
  "https://api.bytnode.com/v1/basis?symbol=BTCUSDT"

# Two fields only
curl -H "X-API-KEY: $BYTNODE_KEY" \
  "https://api.bytnode.com/v1/basis?symbol=BTCUSDT&fields=basis_pct,timestamp"

# Dotted notation for a nested field
curl -H "X-API-KEY: $BYTNODE_KEY" \
  "https://api.bytnode.com/v1/options/summary?asset=BTC&fields=open_interest.total_usd"

An unknown field is refused, with a suggestion of the closest one rather than a silence:

422
{
  "detail": "Champ inconnu : 'basis_percent'. Vouliez-vous dire 'basis_pct' ?"
}

#Reading an empty field

A null or an empty list does not prove the absence of the phenomenon: it may just as well mean that the phenomenon does not exist for this asset. Confusing the two leads to false statements, such as “no liquidation” when the asset is a stablecoin, which has no futures market.

The snapshot removes the ambiguity with the unavailable key, present only when at least one requested field is empty:

ReasonTypeDescription
not_applicablestructuralThe metric makes no sense here: a field derived from the futures market on a spot stablecoin, or options on an asset other than BTC and ETH. No amount of collection would change it.
no_api_keyconfigurationThe upstream source is not plugged into this installation: the data was never collected. It is an infrastructure gap, not a market fact.
no_datamarketA real absence of data over the window asked for. The only case you can draw a conclusion from.

The detail, with the coverage key that says how many venues a figure was built on, is on the Snapshot page. To know in advance what an asset can serve, query its capability report.

#The errors

The detail of an error is carried by the detail key. Refusals tied to the plan (rate limit, monthly quota, family, stream, key) also carry the X-Deny-Reason header with the reason; time-based refusals add retry_after in the body and Retry-After as a header: one second on the rate limit, one hour on the monthly quota.

{
  "status": "error",
  "timestamp": 1775648290510,
  "detail": "Debit depasse : votre offre autorise un nombre limite de requetes par minute.",
  "retry_after": 1
}
CodeMost frequent causeWhat to do
400
Request refused
An unknown or disabled symbol, a depth beyond the field’s cap, an indicator parameter out of bounds.The response body names the offending value and, for a symbol, lists the ones that are accepted.
403
Refused by the plan or by the API key
Four reasons, named by the X-Deny-Reason header: API key missing, invalid or revoked (key); data family outside the plan (family); WebSocket stream outside the plan (websocket); or a history depth beyond the plan’s window, whose detail starts with « Profondeur d’historique hors offre ».On key, check that the header really is sent: some HTTP clients drop it after a redirect. On family and websocket, the data exists but is not in your plan. On depth, the detail gives the maximum limit to use.
422
Missing or malformed parameter
symbol missing, timeframe outside the list, multi-timeframe field requested without the @tf suffix, unknown field in ?fields=, invalid JSON body.On ?fields=, the response suggests the closest field. On a timeframe, it lists the accepted values.
429
Rate or quota exceeded
Either more requests per minute than your plan allows, or too dense a burst (X-Deny-Reason: rate, Retry-After: 1); or the account’s monthly quota is exhausted (X-Deny-Reason: quota, Retry-After: 3600).On rate, wait the second given by Retry-After. On quota, the counter restarts on the first day of the month (UTC); you can also change plan from the console.
503
Momentary unavailability
A read dependency is recovering, or the stream’s concurrent connection cap has been reached.Retry after the delay carried by Retry-After. The error is transient by construction.
500
Unexpected error
A fault on the service side, never caused by the request.Retry; if the response persists, report it with the timestamp carried by the response.

The Error codes page goes back over each case with the exact messages and the errors specific to the indicators and to the real-time stream.

#Response headers

There is no counter header on normal responses: the state of the quota is followed in the console, which warns at 80 % then at the first refused request. Two headers only appear on a refusal.

HeaderTypeDescription
X-Deny-ReasonstringThe reason for a refusal tied to the plan: rate (rate limit), quota (monthly quota), family (family outside the plan), websocket (stream outside the plan) or key (key missing, invalid or revoked).
Retry-AfterintegerPresent on 429 and on 503. The number of seconds to wait before retrying: 1 on an exceeded rate limit, 3600 on an exhausted monthly quota. Respect it rather than inventing a delay.