API Authentication, Key Rotation and Errors
Telemetr.io authenticates REST requests with an API key. This guide covers the request header, key rotation and how to respond to access, billing and request errors.
Authenticate
Send your selected API key in x-api-key on every request. Obtain the current key from @telemetrio_api_bot using /api_key.
curl --fail-with-body "https://api.tlmtr.io/v1/usage/info" \
-H "x-api-key: $TELEMETRIO_API_KEY"
Change a key
Send /api_key, choose Credits API key or Subscription API key in the separate rotation prompt, and confirm. Cancelling leaves the current key unchanged. Another /api_key command only retrieves the current key.
After a confirmed change, update the secret in every integration that uses that key. The old key may remain accepted for up to 60 seconds. Your plan, balance, billing period and used allowances are preserved. If delivery of the new key is interrupted, use /api_key to retrieve the current secret.
Keep keys in backend secret storage. Never log them or include them in browser bundles. Contact support if you cannot access the bot to change an exposed key.
Error bodies
Use the HTTP status and the documented body for that operation. Application errors return JSON with a human-readable message. Additional fields depend on the error; existing numeric fields remain at the top level.
Ordinary errors return a human-readable message:
{"message": "Channel not found"}
Insufficient credits (402, code: insufficient_credits) use integer milli-credits (1000 mc = 1 credit):
{
"code": "insufficient_credits",
"message": "Insufficient credits. Top up your credit balance and retry.",
"cost_known": true,
"total_cost_mc": 801,
"available_mc": 500,
"shortfall_mc": 301
}
When cost_known is true, shortfall_mc is the amount missing from the available balance. Some billing denials report only the balance, without the rejected request's price. In that case the response explicitly marks the cost as unknown:
{
"code": "insufficient_credits",
"message": "Insufficient credits. Top up your credit balance and retry. The exact request cost is unavailable.",
"cost_known": false,
"total_cost_mc": 0,
"available_mc": 0,
"shortfall_mc": 0
}
Here available_mc remains the reported balance. The zero values in total_cost_mc and shortfall_mc are compatibility placeholders, not a free request or a zero deficit. Check cost_known before using these amounts; branch on HTTP 402 or insufficient_credits to recognize the error.
Quota exhaustion (426, code: quota_reached) reports the exhausted counter:
{
"code": "quota_reached",
"message": "The requests quota has been reached. Wait for the quota to reset or upgrade your plan.",
"name": "requests",
"used": 1000,
"limit": 1000
}
Snapshot errors have a stable code and may contain an object in details:
{"code": "SNAPSHOT_TOO_LARGE", "message": "Snapshot is too large", "details": {"max_channels": "50000", "matched_count": "50001"}}
Messages are illustrative; branch on status and stable codes instead of matching message text. A reported matching count can be a lower bound when the scan stops at the limit.
Invalid request parameters or bodies, unknown API routes, unsupported HTTP methods, and request rate limits also return JSON with code and message. For example:
{"code": "not_found", "message": "The requested API endpoint or resource was not found."}
HEAD responses have no body. Responses generated outside the application, such as proxy errors, may use a different format.
Choose the right action
| Status | Meaning | Action |
|---|---|---|
400 | Invalid input; some endpoints also use it for disabled post search or verified-only restrictions | Inspect the message and check the relevant input or access setting |
401 | Missing or invalid credential | Check the selected key and header |
402 | Insufficient available credits | Top up credits; use shortfall_mc only when cost_known is true |
403 | Feature access is not enabled | Check the plan or separately configured access |
404 | A resource read cannot find an accessible resource | Verify the ID and account; snapshot deletions use a result flag instead |
405 | Unsupported HTTP method | Use a method listed in the Allow header |
410 | A retained snapshot or diff has expired | Use an active resource |
412 | Key/subscription is inactive | Restore the appropriate active access |
422 | Invalid request body, or snapshot/current matching set is too large | Inspect code and message; correct the body or narrow the filters |
426 | A usage allowance is exhausted | Wait for renewal or change the allowance |
429 | Request rate, active resource capacity or concurrent operation conflict | Inspect the error, Retry-After and x-ratelimit-after |
503 | A dependency is temporarily unavailable | Retry eligible operations with backoff |
The per-key rate limiter currently allows a sustained 20 requests/second with a burst allowance of 50. Rate-limit errors use code: rate_limit_exceeded and include x-ratelimit-after (seconds), x-ratelimit-limit, and x-ratelimit-remaining. Separate resource and concurrency limits also apply to snapshots.
Temporary snapshot conflicts such as SNAPSHOT_CREATION_IN_PROGRESS, DIFF_CREATION_IN_PROGRESS and SNAPSHOT_MUTATION_IN_PROGRESS can be retried after Retry-After. For SNAPSHOT_LIMIT_REACHED or DIFF_LIMIT_REACHED, release capacity or wait for expiry; a rapid retry does not free storage.
For transient failures on reads, use bounded exponential backoff with jitter. Creating a channel, snapshot or diff changes server state: an uncertain timeout does not prove that creation failed. Check the existing resource/list result before repeating a creation request. See snapshot retries.