xdataapi.io

Errors

Status codes, error codes and what to do.

Errors are JSON with a stable code, a human message and the request_id. No error is charged.

{ "error": { "code": "no_credits", "message": "balance is zero; buy a credit pack" }, "request_id": "..." }

Match on code, never on message. The code is part of the contract and will not change under you; the message is written for a person and may be reworded.

StatusCodeMeaningWhat to do
400bad_requesta parameter is missing or malformedfix the request
401missing_key, invalid_keyno key, or a revoked keycheck the header
402no_creditsbalance is zerobuy a pack
403access_deniedX does not serve this object to the reading sessiontry later, or a different object
403product_unavailablesearch product not available, for example Topuse Latest
404not_foundno such user or tweet, or it is protectednothing
429rate_limitedover your requests-per-second limitwait retry-after seconds
503upstream_rate_limited, no_account, busyX or our pool is saturated right nowretry after retry-after seconds, with backoff
502upstream_error, query_id_stale, request_rejectedX changed something on its sideretry once; if it persists we are already paged
500internalour bugsend us the request_id

RFC 9457 problem+json

Send Accept: application/problem+json and the same failure comes back in the shape a generic HTTP client already understands. Nothing new is reported: type, title, status and detail are the registered names for what error.code and error.message already said, and the native error object is still there, so one parser reads either shape.

{
  "type": "https://xdataapi.io/docs/errors#no_credits",
  "title": "Balance is zero",
  "status": 402,
  "detail": "balance is zero; buy a credit pack",
  "code": "no_credits",
  "error": { "code": "no_credits", "message": "balance is zero; buy a credit pack" },
  "request_id": "..."
}

Without that header you get the native shape, which is what both SDKs read. Neither is going away.

Retry policy we recommend

Retry 503 and 502 up to three times with 2, 4 and 8 seconds between attempts. Do not retry 4xx. Because failed requests are free, retries never cost credits.

Read retry-after when it is present rather than guessing, and read RateLimit on every response to throttle before a 429 happens at all. See Authentication for the rate ladder.

Every code

missing_key

401. No key was sent. Put it in x-api-key, or send Authorization: Bearer xd_live_…. Free.

invalid_key

401. The key is unknown or has been revoked. Check it has not been deleted in the dashboard, and that you are not sending a key from another environment. Free.

rate_limited

429. Over the account's requests-per-second limit, which is shared by every key on the account. Wait retry-after seconds. The limit and what is left of it are on every response in the RateLimit header, so a client that reads it need never hit this. Free.

no_credits

402. The balance is zero. Buy a pack in the dashboard. There is no overage and no invoice: the API stops rather than spending money you did not agree to. Free.

bad_request

400. Something about the request itself is wrong: a missing required parameter, a malformed cursor, a batch list over 100, an unparseable body. The message names the problem. Retrying unchanged will fail again. Free.

not_found

404. There is no such user or tweet, or it is protected, suspended or deleted. Not a fault and not retryable. Free.

access_denied

403. X refused to serve this object to the session that asked (its error 37). Often object-specific rather than account-wide, so another read may well succeed. Free.

product_unavailable

403. The search product asked for is not available, typically Top. Use Latest. Free.

upstream_rate_limited

503. X is rate limiting our pool right now. Retry after retry-after seconds with backoff. Free.

no_account

503. No healthy upstream account is available for this read at this moment. Transient; retry with backoff. Free.

upstream_error

502. X answered with something we could not use. Retry once. If it persists, it is already paging us. Free.

query_id_stale

502. X rotated the identifiers behind its own site and our client has not caught up yet. This is the failure mode the whole repair loop exists for; it is measured on the status page and fixed in minutes, not days. Retry with backoff. Free.

request_rejected

502. X rejected the shape of the upstream request. Same handling as upstream_error. Free.

billing_disabled

503. Card checkout is not configured on this deployment. Nothing you can fix from the client. Free.

internal

500. Our bug. Send the request_id to hello@xdataapi.io and we will find the exact call in the logs. Free.

On this page