Errors, n8n and limits
Errors come in one envelope { error, description, data }. The main codes:
- channel_not_found (404) — no such channel_id (or it is not yours, not selected for the key, or inactive).
- not_found (404) — no such send, subscription or delivery.
- forbidden (403) — the key lacks the permission for this action (see "Key permissions").
- line_license_expired (402) — the line licence has expired; renew the line.
- idempotency_conflict (409) — the client_msg_id was already used for a different send.
- replay_unavailable (409) — only a failed delivery with access still in place can be replayed.
- outside_24h_window (422) — the 24-hour window is closed, plain text will not go out (send a template).
- invalid_message (422) — the channel refused the content, the template is not found / not APPROVED, note / voice do not fit the file type, or chat_type / reply_to contradict the channel or the conversation.
- template_error (422) — Meta refused the template create or edit; reason in description, codes in data.
- invalid_request (400) — the body, query params or a header failed validation (including a media_url not from POST /media/ and a missing Idempotency-Key); per-field detail in data.fields.
- invalid_webhook_url (400) — the URL is not https or is a private address.
- storage_quota_exceeded (413) — the file storage quota is used up.
- unauthorized (401) — the key is missing, malformed or revoked.
- rate_limited (429) — rate limit exceeded; how long to wait is in data.retry_after_seconds and in the Retry-After header.
- method_not_allowed (405) — that HTTP method is not supported on this endpoint.
- internal_error (500) — a failure on our side; retrying is safe, a send repeated with the same client_msg_id will not be delivered twice.
Rate limits are counted per minute, as a rolling window, separately for each kind of request. The values below are the defaults; they can be raised for your project.
| Kind of request | Per key | All keys of a tenant |
|---|---|---|
| Reads: channels, history, templates, /allowed/, send outcome | 1200 | 6000 |
| Sending: POST /messages/ | 600 | 3000 |
| Provider calls: POST /media/, template create, edit and delete, template health | 60 | 300 |
| Management: webhook, secret rotation, subscriptions, catch-up and replay | 30 | 150 |
Each key has its own budget, and the tenant ceiling stops new keys from multiplying throughput. Template health checks run at most two at a time per key. Over the limit you get a 429 in the same envelope plus a Retry-After header — respect it instead of retrying blindly.
n8n. There is no ready-made node yet, but the integration comes together from built-ins: a Webhook node receives inbound (enable raw / binary body, otherwise you cannot verify the HMAC), and an HTTP Request node sends replies with an Authorization: Bearer header.
- Webhook node: enable raw / binary body and verify X-Wahub-Signature-V2 against the raw body.
- HTTP Request node: POST to /messages/ with an Authorization: Bearer gw_… header.
Limits worth keeping in mind while designing your integration:
- Creating templates through Gateway API: text header/body/footer only; no buttons or media headers.
- No exclusivity or handoff: a bot and a live operator may both reply (double replies).
- Several consumers may subscribe to one channel — all of them receive the event.
- Media is served as a path on our host and needs the same key; there is no public link.