Zapnoty — Errors, limits, retry

API Documentation

REST API for notifications via Telegram and Max. Subscribers, OTP, broadcasts, forms, helpdesk.

Error codes

API returns standard HTTP codes with JSON body. The code field is a stable machine-readable identifier in lowercase snake_case (e.g. subscriber_not_found); retryable indicates whether the request can be retried; docs_url links to the code description.

Error format:

{
"error": "Подписчик не найден",
"code": "subscriber_not_found",
"retryable": false,
"docs_url": "https://zapnoty.ru/docs/errors#subscriber_not_found"
}

400 — Invalid request or validation error (bad_request, validation_failed, invalid_url, invalid_external_id, mutually_exclusive_identifiers, etc.). Malformed or incomplete JSON in the request body also returns 400 with code validation_failed — always in the standard envelope, never raw text.

401 — Invalid or missing API key (unauthorized, invalid_api_key)

402 — Access blocked: credits exhausted and the grace period has expired (billing_blocked). Paid operations (sending messages, OTP, broadcasts, helpdesk replies, form submissions) are rejected until the plan is renewed or a credit pack is purchased.

403 — No access to resource (forbidden, project_inactive)

404 — Subscriber or resource not found (subscriber_not_found, not_found)

409 — Conflict (conflict, idempotency_conflict, already_subscribed)

429 — Rate limit exceeded (rate_limit_project, retryable: true, Retry-After header)

500 — Internal error or platform unavailable (internal_error, platform_busy, retryable: true)

Limits

Rate limits and field size restrictions.

Rate limit: 300 requests/min per project. Exceeding it returns 429 Too Many Requests.

Message text: up to 4,000 characters.

Buttons: up to 3 rows, up to 3 buttons per row.

Media: up to 20 MB (photo), 50 MB (video/document).

Broadcast: up to 100,000 subscribers per broadcast.

OTP: code TTL 5 min by default (1–30), 3 attempts by default (1–10), 1 active code per (subscriber, purpose) pair.

Tags: up to 20 tags per project, tag length up to 64 characters.

Permissions: up to 20 per project.

Templates: up to 100 per project.

Projects and team members: limits depend on the plan (Free — 1 project / 1 member; unlimited on higher plans). CSV export is available from the Basic plan.

Forms: up to 10 per project, up to 40 routes per form.

Webhook endpoints: up to 5 per project.

Drip campaigns: up to 50 steps per chain, up to 100 scheduled entries per project.

X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are returned on every /v1/send (Stripe/GitHub/AWS style). On exceeded limit — HTTP 429 + Retry-After. SDKs and integrations should throttle proactively via X-RateLimit-Remaining without waiting for 429.

Error handling & retry

Recommendations for handling API errors and retry strategies.

retryable: true — the error is temporary (429, 500, platform_busy). Use exponential backoff; when the Retry-After header is present, wait the number of seconds it specifies.

retryable: false — retrying won't help (400, 401, 403, 404, 409). Fix the request before resending.

Retry-After — on 429 (and 425/503) this header tells how many seconds to wait. Zapnoty rate limit for /v1/send: 300 requests per minute per project.

Idempotency-Key: for safe retry of POST /v1/send pass a unique Idempotency-Key header (8–128 characters from [A-Za-z0-9_-]). The same key within 24h returns the cached successful response or recorded error — no side effects. Use it for retry-heavy workloads.

Webhook delivery: outgoing Zapnoty webhooks have their own 24-hour retry cycle on a Stripe-style schedule (T+30s, +2min, +10min, +1h, +6h, +24h). Each attempt refreshes the timestamp and signature. Delivery log is visible in the cabinet → project → settings → Webhook.

Related sections