API troubleshooting: common errors
Every endpoint in the reference is marked Planned today: it is the published contract and does not answer yet. This page lists the errors the API will return, so your code can handle them from day one.
Read the error first #
Every error answers a 4xx or 5xx status with the same body:
{ "error": { "code": "forbidden", "message": "…" } }
message is a plain English sentence that says what went wrong. Log it, but branch your code on code, never on message.
401 unauthorized #
The API did not accept your token. Check, in this order:
- The header is exactly
Authorization: Bearer <token>, with the wordBearerand one space. - The token was copied in full. It is shown only once, when you create it.
- The token is still active. In Users › API & MCP, the Access tokens table shows each token's expiry and status, and Show revoked tokens lists the old ones.
- If it expired or was revoked, create a new one (or Rotate it) and update your environment variable.
403 forbidden #
The token is valid but lacks the permission the endpoint needs. Each endpoint in the reference lists its permission, such as can_fan_read or can_sales_read.
- Find the permission in the endpoint's Permission column.
- In Users › API & MCP, press Edit on the token and tick it.
- Call
GET /v1/workspace: the answer lists what the token may do.
A 403 also comes back when a token that is not an owner token sends the LanaChat-Workspace header. Remove it.
429 rate_limited #
Each token may send 600 requests per minute. Every answer carries RateLimit-Remaining and RateLimit-Reset.
- Wait the number of seconds in
Retry-After, then try again. - Page through lists with
limit=100instead of one call per item. - Sending messages to fans is also bound by Telegram's own limits: see Telegram accounts and pools.
The other codes #
| Status | code | What to do |
|---|---|---|
| 400 | invalid_request | A field is missing or has the wrong format: message says which |
| 402 | insufficient_balance | Top up before buying |
| 404 | not_found | The id does not exist in this workspace: check you use the right token |
| 409 | conflict | The change breaks a rule, or an Idempotency-Key was reused with a different body |
| 500 | server_error | Retry later with the same Idempotency-Key |
Send an Idempotency-Key on every POST: a retry then never does the work twice. The helper in the quick start retries 429 and 5xx for you.
Webhooks that fail #
A delivery counts as failed when your server does not answer a 2xx within 10 seconds.
- Answer fast. Return
2xxat once, then do the slow work in the background. - Check the signature on the raw body, before any JSON parsing. A body parsed and re-serialized never matches.
- Check your server's clock. A timestamp older than 5 minutes is refused by the sample code, so a clock that drifts rejects every delivery.
- Accept both
v1values during a secret rotation. - Test with
POST /webhooks/{id}/test(Planned), which sends aping, and resend one delivery with/deliveries/{delivery_id}/retry(Planned) once you fixed your side.
Failed deliveries are retried 8 times over about 24 hours. After 3 days of failures the endpoint is paused; resume it with PATCH /webhooks/{id} (Planned). The same event can arrive twice: ignore duplicates by id. See Webhooks.
Still stuck? #
Open the help bubble at the bottom right of the Console and write to the team with the endpoint, the status, the code and the time of the call. Never paste the token itself. See Get help.