Errors and limits
Every status and error code /notify can return, what caused it and what to do next, plus the documented request, rate and plan limits.
Errors come back as JSON with a single error code. Branch on the code, not on the status alone:
two different 403 and two different 429 responses need different handling.
{ "error": "INVALID_TOKEN" }Error codes
Link to this section| Status | Code | What happened | What to do | Retry |
|---|---|---|---|---|
400 |
INVALID_PAYLOAD |
Malformed JSON or form data, a field that breaks its rules, an unsupported image, data over 4 KiB, or a generated push over 3,800 bytes. |
Fix the request. | No |
400 |
INVALID_IDEMPOTENCY_KEY |
The Idempotency-Key header is missing or malformed. |
Send a stable key of 8 to 128 allowed characters. | No |
401 |
INVALID_TOKEN |
The token is missing, malformed, unknown, paused, expired or revoked. | Check the key in Sources, or create a new one. | No |
403 |
ATTACHMENTS_DISABLED |
Image attachments are temporarily switched off. | Send the event without images, using a new idempotency key. | No |
403 |
CRITICAL_SEVERITY_DISABLED |
Critical alerts are temporarily switched off. | Use another severity only if it truthfully describes the event; otherwise wait. | No |
403 |
TODO_DISABLED |
Checklists are switched off, and the request carried todo. |
Send the alert without todo if it is still useful on its own. |
No |
405 |
METHOD_NOT_ALLOWED |
The request used a method other than POST. |
Use POST. |
No |
409 |
IDEMPOTENCY_CONFLICT |
This source already used the key with different content or images. | Resend the original content, or use a new key for a genuinely new event. | No |
413 |
PAYLOAD_TOO_LARGE |
The JSON body was over 16 KiB, or the multipart request was over the image budget plus 64 KiB. | Send less: shorter data, smaller or fewer images. |
No |
423 |
ACCOUNT_INACTIVE |
The account that owns the source is deleted, being deleted, suspended or otherwise inactive. | Do not retry until the account is restored or support has resolved it. | No |
429 |
RATE_LIMITED |
This source went over its accepted-requests-per-minute limit. | Wait for Retry-After, then retry with the same key. |
Yes |
429 |
ACCOUNT_RATE_LIMITED |
All of the account’s sources together went over the per-account limit. | Wait for Retry-After, then retry with the same key. |
Yes |
500 |
INTERNAL_ERROR |
Zona could not confirm the alert was accepted. | Back off with jitter and retry with the same key and content. | Yes |
503 |
SERVICE_UNAVAILABLE |
Alert intake is temporarily paused by a fail-closed service switch. | Wait for Retry-After, then retry with the same key and content. |
Yes |
Retry-After on 429 and 503 is a whole number of seconds. Retry network failures, 429 and
5xx only, always with the original key, body and images. The full retry policy, with code, is in
Idempotency and retries.
Limits
Link to this sectionLimits are set per plan, and the operator can tune them without an API change, so live values can differ from the documented defaults below.
Request
Link to this section| Limit | Value |
|---|---|
| JSON request body | 16 KiB |
| Multipart request body | The image budget plus 64 KiB |
title |
1 to 120 characters |
body |
1 to 2,000 characters |
category |
1 to 80 characters when present |
severity |
low, medium, high or critical when present |
data |
A JSON object of at most 4 KiB serialized as UTF-8 |
todo |
Up to 20 entries of 1 to 200 characters |
| Images | Up to five PNG, JPEG or WebP files sharing the image budget |
| Generated push payload | 3,800 UTF-8 bytes |
| Limit | Guest | Standard |
|---|---|---|
| Accepted requests per source | Set per plan, shown in the app | 60 in a rolling minute |
| Accepted requests per account, across all sources | Set per plan, shown in the app | 20 in a rolling minute |
| Image budget per alert | 1 MiB | 5 MiB |
| Active sources | 1 | 3 |
| Unrevoked access keys | Set per plan, shown in the app | 10 per source, 10 across the account |
| Registered phones | 1 | 10 |
| Inbox retention | 1 day | 7 days |
Guest accounts also have an hourly cap on accepted alerts, so a guest can receive ACCOUNT_RATE_LIMITED well
below the standard per-minute numbers. The app’s account usage shows the limits that apply to you.
Zona Plus accounts use the premium plan. Its documented values are a 20 MiB image budget, 30-day inbox retention and up to 25 registered phones.
Staying under the rate limit
Link to this sectionRate limits count accepted alerts, per source and per account. If a job can burst, for example one
alert per failing test, send a single summary alert with the details in body, a todo list or an
image instead. When you do get a 429, wait for Retry-After and retry with the same key; an alert
that was never accepted cannot be duplicated.