Error codes
An error always says what was wrong and, when that is possible, what should have been written instead. This page lists the cases, channel by channel, and separates what deserves a retry from what deserves none.
#The shape of an error
The detail is carried by the detail key. On validation errors, it names the offending value and, when a finite list exists, enumerates it.
{
"detail": "Symbole 'PEPEUSDT' inconnu. Valeurs acceptees : BTCUSDT, ETHUSDT, ..."
}Refusals tied to the plan have a fixed shape, set by the gateway: status, timestamp and detail, plus retry_after on time-based refusals (also present in the Retry-After header). The X-Deny-Reason header names the reason: rate, quota, family, websocket or key.
{
"status": "error",
"timestamp": 1775648290510,
"detail": "Debit depasse : votre offre autorise un nombre limite de requetes par minute.",
"retry_after": 1
}The depth 403 is returned by the route itself, without X-Deny-Reason: its detail always starts with « Profondeur d’historique hors offre » and gives the maximum usable limit on that timeframe. The windows per plan are on the Usage limits page.
#HTTP codes
| Code | Cause | Fix |
|---|---|---|
400Request 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. |
403Refused 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. |
422Missing 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. |
429Rate 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. |
503Momentary 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. |
500Unexpected 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 most frequent confusions
| Symptom | Real cause |
|---|---|
| 403 while the key is valid | Read X-Deny-Reason. family: the family of this endpoint is not in your plan. websocket: the stream is not in it. A detail « Profondeur d’historique hors offre »: the request goes back beyond the window of the plan. key with no apparent reason: an HTTP client that drops custom headers after a redirect; call the final URL. |
| 429 while the pace is low | The monthly quota of the account is exhausted (X-Deny-Reason: quota, Retry-After: 3600), not the rate limit. It restarts on the first day of the month, in UTC, or as soon as the plan changes. |
| 422 with no clear message on a snapshot | A multi-timeframe field asked for without its @tf suffix, or the opposite on a single-form field. |
| 400 on a depth that looks reasonable | Every snapshot field has its own ceiling, in its own unit. The CVD stops at 200 windows, the inter-venue spreads at 50. |
| 422 on a timeframe that is valid elsewhere | The long/short ratio refuses 1m, the intraday macro instruments refuse 30m, and the week only exists on the indicators. |
| An empty response that is not an error | A stablecoin on a futures metric, or options on an asset other than BTC and ETH. The unavailable key of the snapshot says which of the three reasons applies. |
| A parameter ignored | Unknown snapshot keys are silently ignored. A misspelt field is simply absent from the response. |
#Indicators
Validation follows a fixed order (timeframe, number of results, symbol, parsing of the indicators, ceiling rule, reading of the candles), and the first failure wins. A corrected body can therefore reveal a second error.
| Case | Code |
|---|---|
| Invalid timeframe, results below 1, unknown symbol | 400 |
| Empty indicators list, or an entry that is not an object | 400 |
| Missing id or type key, id malformed for this type | 400 |
| Unsupported type | 400 |
| Unknown parameter for this type (obv with a period, for example) | 400 |
| Parameter of the wrong type, or below its minimum | 400 |
| macd or adosc with fast greater than or equal to slow | 400 |
| sar with acceleration greater than maximum | 400 |
| Duplicate identifier | 400 |
| Malformed body, more than 50 instances, field too long | 422 |
| results plus warm-up exceeds 1000 | 422 |
| Insufficient data for this timeframe, stablecoins included | 422 |
#WebSocket stream
Every impossible request receives an op: error message that says what was expected: the list of valid symbols, that of the channels, the bounds of depth. Three situations produce not an error but a closure:
| Code | Reason |
|---|---|
| 4003 · ceiling | The plan’s ceiling on simultaneous connections reached. The reason gives the ceiling. A disconnection frees its slot at once. |
| 4003 · client too slow | The send queue has overflowed ten times. Consume faster, or reduce the number of channels. The reason distinguishes the two cases. |
| 4001 | Explicit auth frame refused: the key it carries is invalid. |
| 4002 | Session never authenticated within five seconds. A residual case, since the key is checked at the handshake. |
The key is checked at the handshake, before the opening: a missing or invalid key, or a plan without the stream (Free), receives a 403 at the handshake, with X-Deny-Reason key or websocket. A 429 there signals too high an opening rate. Once connected, a channel whose family is not in the plan receives op: error (« canal … hors offre : la famille … n’est pas incluse dans votre abonnement ») and the whole subscription is refused. See Usage limits.
#MCP server
The errors follow a single pattern, Erreur (HTTP NNN) : message, so that an agent has only one case to recognise. Every tool call is judged as a REST request with the client’s key: a 403 for a family outside the plan or a 429 for quota come back as they are, with their detail. Two families are specific to it:
- Unknown metric: the message lists the forty-six valid metrics.
- Invalid targeting: two targets at once, missing target, wrong target, or a target passed to a whole-market metric. The error names the expected parameter, and it is raised before any network call.
A server fault gives rise to an automatic retry before being reported. A timeout returns Erreur (HTTP 504) after thirty seconds.
#Retry strategy
Not everything can be replayed. Replaying a faulty request produces exactly the same response, and consumes quota for nothing.
def should_retry(code: int) -> bool:
"""What is transient, and what never will be."""
# 429 and 503 will pass: the server says when.
if code in (429, 503):
return True
# 500: a fault on the service side, a retry makes sense.
if code == 500:
return True
# 400, 403, 422: the request is at fault. Replaying it as is will
# produce exactly the same response.
return False- Respect
Retry-Afterrather than inventing a delay: the server knows when it will be ready. - Bound the number of attempts. Three or four are enough: beyond that, the problem is not transient.
- Do not replay a 4xx, 429 aside. Correct the request.
- On the stream, reconnect with an increasing delay, and treat a
4003closure as a signal of overload on the client side: reconnecting without changing the consumption will reproduce the cut.