Errors and rate limits
The shape of an error
Section titled “The shape of an error”{ "error": { "code": "WINDOW_CLOSED", "message": "Free-form messages are only delivered within 24 hours of the recipient's last message. Send a template instead." } }A validation failure adds details — the offending fields, one entry each.
| HTTP | Code | Means |
|---|---|---|
| 400 | BAD_REQUEST |
the body or query did not validate; see details |
| 400 | MISSING_VARIABLES |
a template variable was omitted or blank |
| 401 | UNAUTHORIZED |
no key on the request |
| 401 | INVALID_API_KEY |
unknown, revoked or expired key |
| 403 | FORBIDDEN |
the key lacks the scope this route needs |
| 403 | TENANT_SUSPENDED |
the workspace is suspended |
| 404 | NOT_FOUND |
no such message, or not yours |
| 404 | TEMPLATE_NOT_FOUND |
no template with that name and language |
| 404 | NUMBER_NOT_FOUND |
from is not one of your numbers |
| 409 | WINDOW_CLOSED |
free text or media with no open 24-hour window |
| 409 | TEMPLATE_NOT_APPROVED |
Meta has not approved that template |
| 409 | TEMPLATE_NOT_ENABLED |
that template is switched off for this workspace in the console |
| 409 | CALL_ALREADY_ANSWERED |
somebody answered that call first. Not a failure, and never retry it |
| 400 | CALL_PERMISSION_REQUIRED |
they have not agreed to be called from this number |
| 409 | NUMBER_NOT_REGISTERED |
that number has not finished registering with Meta |
| 409 | CHANNEL_NOT_CONFIGURED |
no number of yours can send yet |
| 409 | MEDIA_NOT_ARCHIVED |
sent as a link, and the copy has not been taken yet |
| 410 | MEDIA_EXPIRED |
the attachment was never archived and Meta’s 30 days have run out |
| 410 | MEDIA_UNAVAILABLE |
the attachment is not archived yet and Meta would not serve it |
| 429 | TOO_MANY_REQUESTS |
over the per-key rate limit |
| 500 | INTERNAL_ERROR |
our fault. Retry with the same idempotencyKey |
| 502 | MEDIA_UNAVAILABLE |
Meta could not be reached for those bytes |
What to retry
Section titled “What to retry”429, 500 and 502 are worth retrying with backoff — always with the same
idempotencyKey, so a retry of a send that actually succeeded does not send twice.
4xx other than 429 will not improve on a second attempt. Fix the request.
Rate limits
Section titled “Rate limits”Per key, not per IP address, so one workspace’s traffic is its own.
| Surface | Limit |
|---|---|
| sending and template preview | 60 requests / minute |
| building and running campaigns | 60 requests / minute |
| every read — message log, media, discovery, calls, campaigns | 240 requests / minute |
Over the limit answers 429 TOO_MANY_REQUESTS. The counter is keyed on the key’s prefix,
so spreading your traffic across more servers does not buy more of it, and another
workspace behind the same egress cannot spend yours.