Starkscan
Getting started

Your first error

The handful of responses you hit on a first Starkscan call — what each means and the exact fix.

Your first error

Almost every first-call problem is one of a few responses. Each has a clear fix. Get a key first with Get your first API key.

Quick triage

StatusMeaningFix
401Key missing or invalidSend X-Starkscan-Api-Key: <your key> — no Bearer prefix. See Authentication.
403Valid key, but the route or tier is not allowedUse a route in your tier; batch / advanced-utility routes need a broader tier — see Advanced utilities.
404Route or resource not foundCheck the path shape https://api.starkscan.co/v1/{chain}/... (Base URLs and chains) and that the id exists.
410Requested Sepolia history is before Starkscan's fixed indexed-history starting blockRead the typed boundary fields from the response or /status, then restart the range or cursor traversal at earliestAvailableBlock. Current state and preserved lifecycle facts remain available.
422A token-holder route has no current explicit address-keyed policy (unqualified_token_policy)Terminal: do not retry, treat it as zero holders, or fall back to client-side scanning. See Token holders.
429Rate limit reached for the route classHonor Retry-After; back off per X-Starkscan-Route-Class — see Rate limits.
400API key sent under more than one header (code conflicting_api_key_headers)Send it once, as X-Starkscan-Api-Key.
400Malformed API key header value (code malformed_api_key_header)Remove stray quotes or whitespace.

The error envelope

{
  "code": "rate_limited",
  "message": "Rate limit exceeded; retry shortly",
  "docSlug": "api/rate-limits",
  "requestId": "mzk-..."
}

Log requestId (also returned as X-Request-Id) whenever you report an issue.

Failure response examples

Every failure uses the same envelope with a stable code. The ones you hit first (the message text is illustrative — key off code, not the exact wording):

400 — key sent under more than one header

HTTP/1.1 400 Bad Request
{
  "code": "conflicting_api_key_headers",
  "message": "API key supplied under multiple headers; send it once as X-Starkscan-Api-Key",
  "requestId": "mzk-..."
}

403 — valid key, route or tier not allowed

HTTP/1.1 403 Forbidden
{
  "code": "forbidden",
  "message": "Key is valid but lacks the required route tier or scope",
  "requestId": "mzk-..."
}

422 — token-holder policy review is required

HTTP/1.1 422 Unprocessable Entity
{
  "code": "unqualified_token_policy",
  "message": "token holder enumeration requires an explicit address-keyed policy review",
  "docSlug": "api/errors",
  "requestId": "mzk-..."
}

The route-specific evidence matrix matters. /holders returns this error only when positive indexed fungible evidence exists without a producer policy; unknown or terminal non-ERC20 identities return 404. Screening and analytics gate directly on policy membership, so any unregistered identity returns this 422 regardless of indexed discovery evidence. It is terminal and has no Retry-After: do not retry it, treat it as a zero-holder answer, or make a request-time provider/RPC scan. It is distinct from a token's non-exact 200 holder rows and from an eligible token's temporary retryable 503.

429 — rate limit reached

HTTP/1.1 429 Too Many Requests
Retry-After: 2
X-Starkscan-Route-Class: heavy
{
  "code": "rate_limited",
  "message": "Rate limit exceeded; retry shortly",
  "docSlug": "api/rate-limits",
  "requestId": "mzk-..."
}

Honor Retry-After (seconds) and keep backoff state per X-Starkscan-Route-Class, so a heavy limit does not stall cheap light reads.

Walkthroughs

401 — verify the header

The usual cause is a missing/typo'd header or a Bearer prefix (there is none). Use -i to inspect the response:

curl -i -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
  "${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/status"

A 200 with chain status means auth is wired correctly.

404 — check the base path

Usually a wrong base path. The canonical API-host rule lives in Base URLs and chains — confirm hosted calls use https://api.starkscan.co/v1/..., or app-host compatibility uses https://starkscan.co/api/v1/....

410 — advance to the Sepolia history floor

Sepolia has a fixed indexed-history starting block. An exact older block or transaction, an explicit block range that crosses the boundary, or a cursor asking for the next older page returns 410 with code="history_expired", historyPolicy="fixed_start", historyCompleteness, earliestAvailableBlock, and earliestAvailableAt. Do not retry the same request. Advance the lower bound to earliestAvailableBlock or begin a new cursor traversal. Mainnet is not governed by this Sepolia history boundary.

403 — wrong tier

The route is valid but not in your key's tier (often batch or advanced-utility routes). See Advanced utilities.

422 — choose an eligible token-holder workflow

For /holders, unqualified_token_policy means positive indexed fungible evidence exists but the token lacks a current explicit address-keyed producer policy; unknown or terminal non-ERC20 identities return 404. Screening and analytics test policy membership directly, so every unregistered identity returns 422 regardless of indexed discovery evidence. The response is terminal and has no Retry-After, is not an empty census, and is not a request to retry. It is also distinct from a token's non-exact 200 holder rows and an eligible token's temporary 503. See Token holders.

429 — back off by route class

Honor Retry-After and keep backoff state per X-Starkscan-Route-Class, so a heavy limit doesn't stop cheap light reads. See Rate limits.

Still stuck?

When you ask for help, include the host, the exact route, X-Request-Id, X-Starkscan-Route-Class, the status code, and a short response snippet. Never share your API key or any auth headers — redact them before sending logs.

On this page