Skip to content
Docs
Get API Access
Browse the Documentation

Errors

One error envelope for every failure, ten error codes, and what to do about each one.

The Error Envelope

Every failure, whatever the endpoint, answers with an HTTP status of 400 or above and this body:

JSON
{
  "status": {
    "timestamp": "2026-10-11T14:00:00.000Z",
    "elapsed_ms": 2,
    "error_code": 1003,
    "error_message": "Market not found",
    "request_id": "req_7Hk2pQ9xLm"
  },
  "error": {
    "code": "not_found",
    "message": "Market not found",
    "retryable": false
  }
}
FieldTypeMeaning
error.codestringThe machine-readable code. Branch on this.
error.messagestringA short human-readable explanation. Its wording can change; do not parse it.
error.retryablebooleanTrue when the same request can succeed later unchanged.
error.retry_after_msinteger, optionalThe exact wait before retrying, on rate and stream-quota errors.
status.error_codeintegerThe numeric form of error.code (1000 to 1009), 0 on success.
status.error_messagestringThe same text as error.message.
status.request_idstringIdentifies this request in our logs. Quote it when you write to us.

The contract also allows an optional error.details object; the API does not send one today, and a validation error does not name the parameter that failed.

Error Codes

invalid_requestHTTP 400error_code 1000not retryable

A parameter failed validation (a wrong type, a value outside its bounds, a malformed ID), the cursor does not belong to this query, or time_start is not before time_end. The message does not name the parameter.

Fix: Check every parameter against the reference: bounds, enums, comma-separated limits and the ID prefixes. Restart pagination without the cursor if the query changed.

unauthenticatedHTTP 401error_code 1001not retryable

The X-API-Key header is missing, or the key is not one the API knows.

Fix: Send the key in the X-API-Key header, exactly as issued. A key that ended more than 30 days ago is removed and answers 401.

forbiddenHTTP 403error_code 1002not retryable

The key is known but its plan is not active: it expired, was suspended, or has not started yet.

Fix: Check the key's state under Account, API keys on cantoncap.cc, renew the plan, or write to api@cantoncap.cc.

not_foundHTTP 404error_code 1003not retryable

The resource does not exist or is not published, the path is unknown, or there is nothing to return (for example no current order book, or no quote in a chart range).

Fix: Resolve IDs with GET /v1/assets/map or the list endpoints. A 404 never says whether an unpublished record exists.

unsupported_capabilityHTTP 422error_code 1004not retryable

The market or source cannot answer this operation (an order book for an AMM market), or the request is larger than the operation supports.

Fix: Check the market model or the venue's capabilities first; narrow the range or the ID list.

rate_limitedHTTP 429error_code 1005retryable

The key used up its requests for the current one-minute window.

Fix: Wait for Retry-After seconds (or error.retry_after_ms), then retry. Spread requests across the window.

quota_exceededHTTP 403error_code 1006not retryable

The request asks for more than the plan allows: a limit above the plan's page size, or a range reaching further back than its history depth.

Fix: Lower limit, or move time_start forward. A larger plan raises both bounds.

conflictHTTP 409error_code 1007not retryable

Raised by administrative write operations only. Public read endpoints do not return it.

Fix: Not applicable to the public API.

source_unavailableHTTP 503error_code 1008retryable

A dependency is briefly unavailable: stored candles not yet published for the range, or the quota service. The issuer X feed preview also answers this while it is disabled.

Fix: Retry with exponential backoff. Candles normally recover within minutes.

internal_errorHTTP 500error_code 1009not retryable

An unexpected failure on the API side.

Fix: Retry once later; if it persists, write to tech@cantoncap.cc with the request_id.

Each endpoint in the reference lists the errors it can answer with and the exact messages.

Handle Errors in Code

const response = await fetch(url, { headers: { "X-API-Key": key } });
const body = await response.json();

if (!response.ok) {
  const { code, message, retryable, retry_after_ms } = body.error;
  switch (code) {
    case "rate_limited":
    case "source_unavailable":
      // Retryable: wait retry_after_ms when given, else back off exponentially.
      break;
    case "unauthenticated":
    case "forbidden":
      // The key is missing, wrong or not active. Alert a human; do not retry.
      break;
    case "quota_exceeded":
      // Ask for less: a smaller limit or a shorter range.
      break;
    case "not_found":
      // The record is unknown or unpublished. Treat as absent.
      break;
    default:
      // invalid_request, unsupported_capability, internal_error
      throw new Error(`${code}: ${message} (${body.status.request_id})`);
  }
}

A full retry loop with backoff is on Rate limits.

Not Every 404 Is an Error
Batch endpoints such as /v1/simple/price leave out IDs they cannot answer for instead of failing, and a currency without an observation is left out of quotes. Check for the key before you read it.

Getting Help

If an error persists and you cannot explain it, write to tech@cantoncap.cc with the request_id, the time, the endpoint and the parameters (never the key). See Support and legal.

Esc
navigateopenEscclose