Skip to content

Errors

Every refusal is JSON with code and error. Branch on code; error is a sentence for people, and it will be reworded.

An answer is never late
Every answer comes at once from what is stored. A token being brought up to the hour behind your answer is not an error: data.reads.refreshing says so, and a pull a few minutes later has the newest hours. See freshness and new tokens.

The shape

{
  "tool": "token_series",
  "ok": false,
  "code": "tool_error",
  "error": "\"base:0x…\" is not in the Blocktronics cache. Use search_tokens to find a cached token.",
  "charged": 0,
  "data": null
}
A tool's refusal keeps the tool's own fields beside code and error; some codes add more, as insufficient does

Every code

400
tool_error

The tool couldn't answer that input: a token Blocktronics hasn't indexed, a metric it doesn't know, a span outside the stored days. error says which, in words.

Fix Fix the input. For a token Blocktronics hasn't indexed, find it with search_tokens or quote it with GET /v1/tokens/{chain}/{token}/ingest.

400
invalid · invalid_chain · invalid_token

The body isn't the JSON the endpoint takes, a query asks for nothing, or an ingest path's chain or address is wrong (base, ethereum or robinhood; 0x and 40 hex characters).

Fix GET /v1/catalog shows each tool's input. The ingest body is optional: {"expect": <quoted credits>}.

401
bad_key · signed_out · key_required · bad_nonce · bad_signature

bad_key: the key is unknown, revoked, ended or mistyped. signed_out: no key was sent. key_required: one of the site's own data feeds was called from outside the site. bad_nonce, bad_signature: a wallet signature (a key from a wallet, or a top-up wallet's proof) was expired, reused or from another wallet.

Fix Send the key as a bearer token in the Authorization header; make a new one on /account#keys if it ended. For data, call the API, not the site's feeds. For a signature, ask for a new message and sign it with the right wallet.

402
insufficient · refused

The balance can't cover it. A query or an ingest answers insufficient with credits, needed, available and a suggested topup; a tool answers refused, its data saying what it takes. Refused before anything ran.

Fix Don't retry: it needs credits, not another attempt. Top up credits on your account, or swap through Blocktronics and earn credits back as rebates.

403
refused · key_scope · not_entitled · ask_first · site_only · topup_not_allowed · over_topup_limit · wallet_unproven

refused: a tool was refused before it ran (a cap on the key or the account). key_scope: the key can't spend credits. not_entitled: the account can't use this yet. ask_first: over the key's ask-me-first line. site_only: a feed that serves the site's pages only; error names the API tool that serves the same. topup_not_allowed, over_topup_limit: the key can't top up, or not that much at once. wallet_unproven: the top-up wallet hasn't signed for the key yet.

Fix Make a new key on your account page, raise its limit, or do it on the site. For site_only, call the tool it names. For wallet_unproven, POST /v1/topup/wallet and sign the message with that wallet, once.

404
unknown_tool

Not a tool the API serves. error lists the ones it does.

Fix Pick a tool from GET /v1/catalog.

409
price

The ingest's quote rose above your expect. credits holds the new figure.

Fix Check the new figure, then POST again with it.

413
too_large

The body is larger than any tool's input.

Fix Send only the tool's input.

422
unsupported_token

Blocktronics doesn't support this token: wrapped natives, stablecoins, wrapped stocks and similar reference assets are left out of holder analytics. Never quoted, built or charged.

Fix Pick another token.

429
rate_limited · credential_cap_reached · topup_day_limit · too_many_quotes

rate_limited: more than 120 requests a minute on one key, or a free daily allowance per address used up. credential_cap_reached: the key spent its daily credit limit; it resets at 00:00 UTC. topup_day_limit: the day's top-ups are used. too_many_quotes (inside a refused top-up): the paying wallet has 20 open quotes.

Fix Wait the Retry-After seconds. A daily limit is raised on your account page.

500
internal

A problem on our side.

Fix Retry with backoff.

503
unavailable

The tool didn't answer just then.

Fix Try again in a minute.

No error is ever billed

Every answer in that list costs nothing, and says so. A retry loop on a transient failure costs you time, not credits; see credits and billing.

Retrying safely

Retry 429 after its Retry-After seconds, and 5xx with exponential backoff. Never retry 400, 401, 403 or 404: they will fail the same way every time, and a tight loop on an auth failure is how an integration gets itself rate limited. Never retry 402 either; it needs credits, not another attempt

TypeScript
const TRANSIENT = new Set(["rate_limited", "internal", "unavailable"]);

async function tool(name: string, input: object, key: string, attempt = 0): Promise<unknown> {
  const res = await fetch(`https://api.blocktronics.xyz/v1/tools/${name}`, {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "content-type": "application/json" },
    body: JSON.stringify(input),
  });
  const body = await res.json();
  if (res.ok) return body;
  // Nothing was charged. Only a transient failure is worth another attempt.
  if (!TRANSIENT.has(body.code) || attempt >= 4) throw new Error(`${body.code}: ${body.error}`);

  const wait = Number(res.headers.get("retry-after")) || 2 ** attempt;
  await new Promise((r) => setTimeout(r, wait * 1000));
  return tool(name, input, key, attempt + 1);
}