API conventions: auth, error codes, rate limits and pagination

Behavior shared by every Xanguard API, collected in one place.

Response Envelope

Every response from a valid REST endpoint is wrapped in a standard envelope. On success, ok is true and the payload is in data. On error, ok is false, the human-readable message is in error, and a stable machine-readable code tells you what went wrong. Some errors add a hint (what to do next) and retry_after (seconds until a retry can succeed; on B2B and CA Search also sent as the Retry-After header).

Requests the server can't parse (bad JSON, wrong field types, body over 64 KB, unknown path) get only the HTTP status with a plain-text or empty body. The /twitter/* twitterapi.io-compatible routes use that service's shape instead (see B2B REST).

{
  "ok": true,
  "data": { ... }
}

{
  "ok": false,
  "error": "Your subscription expired on 01 Oct 2026 10:12 UTC. Renew in @B2B_Xanguard_bot; your key stays the same.",
  "code": "key_expired"
}

Match on code, not on the error text: messages may be reworded, codes will not change.

Authentication

All REST APIs authenticate with a Bearer token in the Authorization header:

Authorization: Bearer <prefix>_your_api_key_here

Each product issues keys with its own prefix (xg_, dt_, cw_, …) — see the API overview table for the full list and issuing bots. Keys are product-scoped, with one exception: a B2B dt_ key also works on the Tweet Alerts endpoints (/v1/accounts…, /v1/ws). B2B (/v1/dt/*), /twitter/* and CA Search additionally accept the twitterapi.io-compatible X-API-Key header. Keys are never accepted in the URL query string on REST endpoints (B2B returns 401 key_in_query; the other APIs return a generic 401).

Error Codes

Common HTTP status codes across the APIs:

StatusMeaning
400Bad request — missing or invalid field
401Authentication failed — missing, malformed, or invalid API key
403Not allowed — plan limit reached, feature not enabled on this key, or no active paid plan
404Resource not found (or no data collected yet)
409Conflict — resource already exists
429Rate limit or daily allowance exhausted — back off and retry
500Temporary server-side failure — retry
503Service temporarily unavailable — retry with backoff

Error code values. Every enveloped error carries one; when no specific code applies it is derived from the status (bad_request, unauthorized, forbidden, not_found, conflict, rate_limited, server_error, service_unavailable). Which API sends which codes: the key_* codes come from B2B (/v1/dt/* and the B2B WebSockets) only; ip_blocked from the B2B WebSockets only; handle_limit_reached from B2B, Community Watch and Convergence Tracker; daily_limit_reached from CA Search. Tweet Alerts (/v1, /v1/ws) and the other product APIs return status-derived codes only (any key problem is 401 unauthorized; no paid plan or a full plan is 403 forbidden), and product WebSockets reject a bad key with a plain-text HTTP 401 before the upgrade.

codeStatusWhat it means / what to do
key_missing401No key was sent, or it was empty. Check the variable or config that holds your key on that machine.
key_in_query401Key sent as ?api_key= on a REST endpoint. Send it in the Authorization: Bearer (or X-API-Key) header.
key_malformed401Not a key for this product (wrong prefix). Copy the full key from the product's bot.
key_unknown401Key not recognised: a typo, a cut-off key, or an old key you regenerated.
key_expired401Subscription expired (the message gives the date). Renew in the bot; the key stays the same.
key_deactivated401Key deactivated. Contact support.
ip_blocked4295 failed logins (missing, wrong or expired key) from your IP within 60 seconds blocked it for 1 hour. Fix the key; the block lifts by itself at the time given. retry_after / Retry-After = seconds left.
handle_limit_reached403Your plan's handle ceiling is full. Remove a handle or upgrade.
rate_limited429Too many requests. Wait retry_after seconds.
daily_limit_reached429Daily allowance used up; resets at 00:00 UTC (retry_after = seconds until then).
service_unavailable / server_error503 / 5xxA temporary problem on our side, not with your request. Retry in about 30 seconds.

WebSocket disconnect codes (login_timeout, too_many_connections, …) are listed on the B2B WebSocket page. B2B Monitoring and CA Search document per-endpoint error tables in their own sections: B2B API and CA Search.

Pagination

Two conventions exist. B2B list endpoints paginate with limit/offset query params (e.g. /v1/dt/followers/{handle}). CA Search uses an opaque cursor: pass the previous response's next_cursor as cursor to continue a truncated result set. Consumer API lists are unpaginated and return the full set.

Rate Limits

SurfaceLimit
Consumer REST (/v1)Per account (all your keys share it), 1-second windows, scales with your plan; excess returns 429 rate_limited with retry_after: 1
B2B REST (/v1/dt)Not per-second rate-limited — 64 KB request-body cap; 5 concurrent WebSocket connections per key
CA Search (/v1/search)10 requests/sec and 20 requests/min per Telegram account (all your keys share it), plus the daily plan allowance
Product APIs (/v1/cw, /v1/ct, /v1/eca, /v1/et, /v1/trending, /v1/pf, /v1/sa)No per-second limit; plan limits (handles, entries, queries) apply
Consumer WebSocket (/v1/ws)10 inbound messages/sec per connection