Error catalogue

Every error the API returns. Error bodies link to their entry via error.doc_url; quote error.request_id (also the X-Request-Id header) when you contact support.

Format

Errors are JSON with a stable machine-readable code. Branch on error.code, never on the message text.

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit of 60 requests per minute exceeded.",
    "doc_url": "https://blockmetric.io/developers/errors#rate_limited",
    "request_id": "req_5f0c1a9e2b7d4c3a8e6f1b20",
    "retryable": true
  }
}

The SDKs (coming soon) will throw BlockmetricError with code, status, requestId and docUrl, and retry automatically where the table says "retry".

Handling errors in code

Retry only what can succeed later (429 and 5xx, after Retry-After seconds); fix everything else. Log request_id with every failure.

const RETRY = new Set(["rate_limited","daily_limit_exceeded","stream_limit","internal_error"])

const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.BLOCKMETRIC_API_KEY}` } })
if (!res.ok) {
  const { error } = await res.json()
  if (RETRY.has(error.code)) {
    const wait = Number(res.headers.get('Retry-After') ?? 5)
    // try again in `wait` seconds
  } else {
    // a problem with the request: error.message says what to change, error.doc_url how
    throw new Error(`${error.code} (${error.request_id}): ${error.message}`)
  }
}

400 invalid_param

Fix the request

Invalid parameter

A query or path parameter has the wrong type or an unknown value, the parameter itself is unknown to the endpoint, or a cursor is malformed. error.param names the parameter. Numeric values outside their range are clamped, not rejected; meta.warnings names them. Also returned when an API key is sent in the URL (?api_key=…): keys are only accepted in headers.

Typical causes

  • A typo in an enum value (side=longs instead of long, venue=binanc).
  • A typo in a parameter name (limt=5, symbol=BTC): the message suggests the closest known name.
  • A non-numeric value for an integer parameter (limit=ten).
  • since, from, to, end or other times not in ISO 8601 (use 2026-10-23T12:00:00Z).
  • A cursor from a different endpoint, taken to other filters, or edited (cursors are signed with the endpoint and its parameters).
  • Parameters that exclude each other: after with cursor, from with sinceMinutes, end without tf.
  • An API key in the query string (api_key, key, token …). URLs end up in logs and browser history.

Fix

  • Read error.message and error.param: they name the parameter and the allowed values.
  • Compare with the parameter table in the API reference or the OpenAPI document.
  • Pass meta.nextCursor unchanged (or follow meta.nextUrl) and keep the other parameters.
  • Send the key in the Authorization header; revoke a real key that was put in a URL.

401 unauthorized

Fix the request

Missing or invalid API key

No key was sent, or the key is malformed (checksum mismatch), unknown, revoked or expired.

Typical causes

  • The Authorization header is missing or not "Bearer <key>".
  • The key was revoked on the account page (or by us after it was found in public), or its expiry date has passed.
  • A copy-paste error cut or changed the key: keys end in a checksum, so a typo is detected without a lookup (keys are bm_live_ + 50 characters; older formats are not accepted).
  • Too many invalid keys from one network answer 429 rate_limited for up to 10 minutes.

Fix

  • Send "Authorization: Bearer bm_live_…" or "x-api-key: bm_live_…".
  • Create a new key on /account/api. The full key is shown once.
  • Check the environment variable your code reads (BLOCKMETRIC_API_KEY in our examples).

403 plan_required

Fix the request

Plan does not include this

The key is valid, but the requested data or feature needs a higher plan.

Typical causes

  • The key of a Free account asked for a whale stop map outside BTC, ETH, HYPE (Pro, Desk and the API plans cover every coin).
  • A heatmap interval outside the plan (free key: 15m, 1h; 1m needs Desk or API Pro), or columns finer than 15 minutes through the deprecated stepMinutes on a free key. The heatmap covers every coin on every plan; a window beyond the plan's heatmap history (free key the last 24 hours) answers 400 invalid_param.
  • Webhooks are part of API Dev and API Pro; GET /stream is part of API Pro.

Fix

  • See the plan table on /pricing/api#compare-plans.
  • Upgrade on /pricing; existing keys pick up the new plan immediately (the plan is looked up on every request).

403 scope_required

Fix the request

Key not scoped for this API

The key is valid, but its scopes do not include this API: a key limited to the Blockmetric Node gateway (scope node) cannot call /api/v1, and a key without the node scope cannot call the node gateway.

Typical causes

  • The api or node box of the key was unticked on /account/api.
  • A key created for the node gateway only is used for the data API (or the other way round).

Fix

  • Tick the missing scope for the key on /account/api (it applies immediately; the node gateway picks it up within 30 seconds).
  • Use a separate key per integration.

403 ip_not_allowed

Fix the request

Address not on the IP allowlist of the key

The key is valid, but it is restricted to an IP allowlist and the request came from another address.

Typical causes

  • The outbound address of the server changed (new host, NAT gateway, IPv6 instead of IPv4).
  • The key is used from a laptop or CI runner that is not on the list.

Fix

  • Add the address or range (CIDR, e.g. 203.0.113.0/24 or 2001:db8::/48) to the key on /account/api.
  • Use a separate key without allowlist for development.

403 origin_not_allowed

Fix the request

Key used from a browser origin it does not allow

The request carried an API key and an Origin header (it came from a web page), and the key does not list that origin under its allowed browser origins. Keys belong on a server: a key in front-end code is visible to every visitor, who can use up your quota (and overage) and your licence duties travel with it.

Typical causes

  • A key in a browser app, a browser extension or a no-code tool that runs in the browser.
  • The page moved to a new domain or sub-domain that is not on the list.

Fix

  • Call the API from your backend and pass the data on to the page.
  • For widgets that need no key, use keyless public access (header "X-Blockmetric-Access: public").
  • If a browser key is intended: add the exact origin (https://app.example.com, or https://*.example.com) to the key on /account/api. Outside browsers an Origin header can be forged: the list prevents accidental embedding, it is not authentication.

403 source_restricted

Fix the request

Exchange data not redistributed

The request asked for raw data of an exchange (single liquidations, trades, order books, tickers, funding or ratios of Binance or Bybit, or candles of a coin that only trades there) that the API does not pass on while the review of the exchange’s terms is pending. Our own figures built from it (sums over venues, totals per hour, spreads) stay available, and meta.restricted names the withheld venues on the endpoints concerned.

Typical causes

  • venue=binance or venue=bybit on /markets, /liquidations, /tape, /orderbook or /flow.
  • GET /candles of a coin without a Hyperliquid market (exchange-only coins such as XAU).

Fix

  • Use the aggregates: /liquidations/summary (per venue and hour), /screener (open interest over venues), the totals of /flow.
  • Omit venue to get the venues the API serves.
  • See /methodology#sources for the status of each source; the changelog announces when exchange data is licensed for the API.

403 https_required

Fix the request

https required

The request reached the API over plain http. The API only answers over https.

Typical causes

  • A base URL starting with http://.

Fix

  • Use https:// in the base URL.
  • The key travelled unencrypted: revoke it on /account/api and create a new one.

404 not_found

Fix the request

Not found

Unknown endpoint, unknown coin or a wallet that is not tracked.

Typical causes

  • A typo in the path (/api/v1/liqmaps/BTC).
  • A coin that is not listed on Hyperliquid (see GET /coins).
  • A wallet address the collector does not track.

Fix

  • List valid coins with GET /api/v1/coins.
  • Compare the path with the OpenAPI document (/api/v1/openapi.json).

405 method_not_allowed

Fix the request

Method not allowed

The API is read-only: every endpoint answers GET (and HEAD / OPTIONS). The Allow header lists the methods.

Typical causes

  • A POST, PUT, PATCH or DELETE request, e.g. from a generic HTTP client default.

Fix

  • Send GET with the parameters in the query string.
  • Webhooks and keys are managed on /account/api, not through the API.

429 rate_limited

Retry

Per-minute limit reached

The account used all requests of the current minute (all keys of the account share the limit).

Typical causes

  • A tight polling loop.
  • Several processes or keys of the same account running in parallel.

Fix

  • Wait Retry-After seconds.
  • Watch X-RateLimit-Remaining and X-RateLimit-Reset (the day: X-RateLimit-Remaining-Day; both windows: RateLimit / RateLimit-Policy), or ask GET /me (it is not counted).
  • Revalidate with If-None-Match instead of downloading unchanged data, or use webhooks (API Dev, API Pro) or the stream (API Pro) instead of polling.

429 daily_limit_exceeded

Retry

Daily limit reached

The account used all requests of the current UTC day.

Typical causes

  • Polling more often than needed over the day.
  • The free key (1,000 requests per day) used for a production workload.

Fix

  • Retry-After gives the seconds until 00:00 UTC; X-RateLimit-Remaining-Day shows the day before it runs out.
  • Cache responses (ETag), poll less often, or upgrade the plan. API Dev / API Pro can enable overage on /account/api (X-Blockmetric-Overage: billed marks billed calls).

429 stream_limit

Retry

Too many open streams

GET /stream only: the account already has the maximum number of live streams of its plan open (API Pro: 2).

Typical causes

  • A second process or a crashed one whose connection is not released yet.
  • Reconnecting without closing the previous connection.

Fix

  • Close one stream; a dropped connection frees its slot within 45 seconds.
  • Retry after Retry-After (15 s); fan out events inside your own system.

500 internal_error

Retry

Internal error

Something failed on our side. No details are exposed.

Typical causes

  • A bug or a temporary database problem.

Fix

  • Retry with exponential backoff.
  • If it persists, contact support with error.request_id (also in the X-Request-Id header).

Missing something? See the API reference or the changelog.

LiveHyperliquid markets 2sOperationalHyperliquid positions & whales 1sOperationalLiquidation heatmap & levels 4sOperationalLighter markets & liquidations 10sOperationalLighter positions & heatmap 2sOperationalLighter RH positions & heatmap 6sOperationalBinance markets 31sOperationalBybit markets 1sOperationalBinance liquidations 10sOperationalBybit liquidations 10sOperationaldYdX positions & heatmap 3sOperationalGMX positions & heatmap 6sOperationalLong/short & open interest history 2mOperationalOrder books & trade flow 1sOperationalOn-chain transfers 2sOperationalSecurity monitor 40sOperationalBlockmetric Sentiment 9mOperationalOfficial news 7mOperationalAlert delivery 2sOperational10:06:28 UTCData: Blockmetric Research · Binance · Bybit