Quick links

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" }
Table, scrolls horizontally when narrow
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 are set per plan, and the operator can tune them without an API change, so live values can differ from the documented defaults below.

Table, scrolls horizontally when narrow
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
Table, scrolls horizontally when narrow
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 section

Rate 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.