Коды ошибок
API возвращает стандартные HTTP-коды с JSON-телом. Поле code — стабильный машинно-читаемый идентификатор в lowercase snake_case (например, subscriber_not_found), retryable указывает, стоит ли повторить запрос, docs_url ведёт на описание кода.
Формат ошибки:
400 — Невалидный запрос или ошибка валидации (bad_request, validation_failed, invalid_url, invalid_external_id, mutually_exclusive_identifiers и т.п.). Битый или неполный JSON в теле запроса тоже возвращает 400 с кодом validation_failed — всегда в стандартном конверте, не голым текстом.
401 — Неверный или отсутствующий API-ключ (unauthorized, invalid_api_key)
402 — Доступ заблокирован: кредиты исчерпаны и grace-период истёк (billing_blocked). Платные операции (отправка сообщений, OTP, рассылки, ответы helpdesk, приём заявок форм) отклоняются, пока тариф не продлён или не куплен пакет кредитов.
403 — Нет доступа к ресурсу (forbidden, project_inactive)
404 — Подписчик или ресурс не найден (subscriber_not_found, not_found)
409 — Конфликт (conflict, idempotency_conflict, already_subscribed)
429 — Превышен rate limit (rate_limit_project, retryable: true, заголовок Retry-After)
500 — Внутренняя ошибка сервера или платформа недоступна (internal_error, platform_busy, retryable: true)
Лимиты
Rate limits и ограничения на размеры полей.
Rate limit: 300 запросов/мин на проект. При превышении — 429 Too Many Requests.
Текст сообщения: до 4 000 символов.
Кнопки: до 3 рядов, до 3 кнопок в ряду.
Медиа: до 20 МБ (photo), 50 МБ (video/document).
Broadcast: до 100 000 подписчиков за одну рассылку.
OTP: TTL кода по умолчанию 5 мин (1–30), по умолчанию 3 попытки (1–10), 1 активный код на пару (подписчик, purpose).
Теги: до 20 тегов на проект, длина тега до 64 символов.
Разрешения: до 20 на проект.
Шаблоны: до 100 на проект.
Проекты и участники команды: лимиты зависят от тарифа (Free — 1 проект / 1 участник, на старших тарифах — без ограничений). Экспорт CSV доступен с тарифа «Базовый».
Формы: до 10 на проект, до 40 маршрутов на форму.
Webhook-эндпоинты: до 5 на проект.
Drip-цепочки: до 50 шагов в одной цепочке, до 100 scheduled-записей на проект.
Заголовки X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset возвращаются на каждый /v1/send (стандарт Stripe/GitHub/AWS). При превышении — HTTP 429 + Retry-After. SDK и интеграциям рекомендуется тормозить проактивно по X-RateLimit-Remaining, не дожидаясь 429.
Обработка ошибок и retry
Рекомендации по обработке ошибок API и стратегии повторных запросов.
retryable: true — ошибку можно повторить (429, 500, platform_busy). Используйте exponential backoff; при наличии заголовка Retry-After ждите указанное в нём число секунд.
retryable: false — повторять бессмысленно (400, 401, 403, 404, 409). Исправьте запрос перед повторной отправкой.
Retry-After — при 429 (и 425/503) заголовок указывает сколько секунд ждать. На стороне Zapnoty rate limit /v1/send: 300 запросов в минуту на проект.
Idempotency-Key: для безопасного ретрая POST /v1/send передавайте уникальный заголовок Idempotency-Key (8–128 символов из [A-Za-z0-9_-]). Тот же ключ за 24 часа вернёт сохранённый успешный ответ или зафиксированную ошибку — без побочных эффектов. Используйте при retry-нагрузках.
Webhook delivery: исходящие webhook'и Zapnoty имеют свой 24-часовой retry-цикл по расписанию Stripe (T+30с, +2мин, +10мин, +1ч, +6ч, +24ч). Каждая попытка обновляет timestamp и подпись. Журнал доставок виден в кабинете → проект → настройки → Вебхук.