Rate limits
:::info No rate limiting is enforced today
There is no request quota on this API, no 429 in normal operation, and no
rate-limit headers on responses. The per-key call-limit fields visible in the
admin center are not applied to this API.
:::
That is a statement about today, not a promise. Treat it as an implementation detail that will change, and build as though limits exist.
Build like they exist
Throttle your own traffic. An unthrottled loop against GET /users on a
large account is a self-inflicted outage, limits or no limits.
Handle 429 now. It costs a few lines and it is in the
error catalog already:
429 → { "error": { "type": "rate_limited", "message": "…" } }
Back off exponentially with jitter and retry — nothing happened, so a retry is always safe.
Read Retry-After if it is present. When limits arrive they will use the
standard header. A client that already respects it needs no change.
Cheaper than polling
The three patterns that generate the most needless load, and what to do instead:
| Instead of | Do this |
|---|---|
| Polling for new SMS | Subscribe to the AccountSMS webhook |
| Polling for ended calls | Subscribe to AccountEndedCalls |
Re-fetching GET /users per request | Cache it. It changes when staff join or leave, not per call. |
Recordings are the honest exception: a recording appears shortly after hangup,
and [] means "not yet". Poll that one — but poll it on a delay after the
AccountEndedCalls event rather than on a timer.
Timeouts
Give requests a generous client timeout. A send goes through a carrier gateway,
and a recording list touches storage. A timeout is not a failure — on
POST /sms/messages the message may have been sent and billed. See
what is safe to retry.