Zapnoty — Тестирование интеграции

Документация API

REST API для уведомлений через Telegram и Max. Подписчики, OTP, рассылки, формы, helpdesk.

Тестирование интеграции

Перед боевым запуском интеграцию стоит проверить. Zapnoty даёт несколько инструментов: тестовые ключи, предпросмотр и dry-run рассылок.

Два ключа на проект

У каждого проекта два API-ключа: боевой zn_live_ и тестовый zn_test_. Это один и тот же проект — общие подписчики, шаблоны и webhook-эндпоинты, разница только в ключе. При создании проекта ответ содержит сразу оба ключа — поля api_key и test_api_key.

Что разрешено тестовому ключу

Тестовый ключ zn_test_ предназначен для проверки ОТПРАВКИ (runtime), а не для управления проектом. Поэтому он разграничен по правам:

Чтение — любые GET-запросы (шаблоны, подписчики, теги, права, вебхуки, журналы, аналитика).

Runtime-операции (замоканы в sandbox): /v1/send, /v1/send/batch, /v1/send/preview, /v1/otp/*, /v1/broadcast, /v1/auth/session, /v1/auth/verify, /v1/events/track, /v1/helpdesk/tickets/*, /v1/helpdesk/request, /v1/test/simulate-event.

Изменение настроек проекта — любой мутирующий запрос (POST/PUT/PATCH/DELETE) к шаблонам, правам, тегам, вебхукам, sender, авто-сообщениям, формам, helpdesk-конфигу (settings/SLA/типы обращений/готовые ответы/правила маршрутизации), custom-bots, планировщику (scheduled/drip/recurring), ротации ключей, удалению подписчиков → 403.

Запрос на изменение настроек с тестовым ключом возвращает 403 со стандартным конвертом ошибки. Так тест-ключ нельзя случайно использовать для порчи проекта: настройка проекта — разовое действие, и его выполняют боевым ключом zn_live_ один раз при настройке.

POST /v1/templates
Authorization: Bearer zn_test_...
{ "key": "welcome", "text": "..." }
→ 403 {
"error": {
"code": "test_key_forbidden",
"message": "Тестовый ключ (zn_test_) не может изменять настройки проекта — это делается боевым ключом"
}
}

Песочница: что такое sandbox-режим

Запрос с тестовым ключом zn_test_ проходит всю API-логику (валидация, rate-limit, журнал доставок, вебхуки) и отвечает точно так же, как боевой — те же ответы и коды ошибок, — но реальное сообщение в Telegram/Max НЕ отправляется (mock-доставка). Sandbox покрывает /v1/send, /v1/send/batch, /v1/otp/send и /v1/broadcast. Записи в журнале доставок помечаются is_test=true и не учитываются в боевой статистике проекта.

Симуляция исхода доставки

В sandbox-режиме в тело /v1/send можно добавить _test_directives, чтобы воспроизвести нужный исход. delivery_outcome: "failed" уводит доставку по failure-пути: запись в журнале со статусом failed и вебхук delivery.failed с reason из failure_reason. Допустимые failure_reason: user_blocked_bot, chat_not_found, bot_banned, invalid_message, rate_limited, platform_unavailable, unknown. Для боевого ключа _test_directives молча игнорируется.

POST /v1/send
Authorization: Bearer zn_test_...
{
"subscriber_id": "550e8400-...",
"text": "Тестовое сообщение",
"_test_directives": {
"delivery_outcome": "failed",
"failure_reason": "user_blocked_bot"
}
}
→ {
"sent": 0,
"failed": 1,
"details": [{
"success": false,
"error": "Симулированный провал доставки (sandbox): user_blocked_bot",
"delivery_id": "..."
}]
}

OTP в песочнице

При вызове /v1/otp/send с тестовым ключом ответ содержит дополнительное поле sandbox_code — реальный сгенерированный код в открытом виде. CI/тест может сразу передать его в /v1/otp/verify без доступа к мессенджеру. Для боевого ключа поле sandbox_code отсутствует.

POST /v1/otp/send
Authorization: Bearer zn_test_...
{ "subscriber_id": "550e8400-..." }
→ {
"sent": true,
"expires_in_seconds": 300,
"sandbox_code": "482915"
}

Предпросмотр сообщения

POST /v1/send/preview рендерит сообщение (шаблон, переменные, подпись) и возвращает итоговый текст без отправки. Удобно проверить, как подставятся vars и какой формат применится.

POST /v1/send/preview
{
"subscriber_id": "550e8400-...",
"template": "welcome",
"vars": { "name": "Анна" }
}
→ {
"rendered_text": "Привет, Анна!",
"format": null,
"text_length": 12,
"has_media": false,
"buttons_count": 0,
"entities_count": 0,
"template_key": "welcome"
}

Dry-run рассылки

Параметр dry_run: true в /v1/broadcast не создаёт рассылку — возвращает размер аудитории под фильтрами, оценку списания кредитов и пример отрендеренного сообщения. Так проверяют фильтры (теги, разрешения) перед реальной отправкой.

POST /v1/broadcast
{
"text": "...",
"tags_all": ["vip"],
"dry_run": true
}
→ { "would_send_to": 342, "estimated_credits": 342, "rendered_sample": "..." }

Проверка вебхуков

Чтобы проверить приём событий, временно укажите в webhook-эндпоинте URL тестового приёмника (webhook.site, ngrok на localhost). Подпись X-Zapnoty-Signature считается так же — проверьте валидацию HMAC. Журнал доставок вебхуков виден в кабинете. Доставки от sandbox-запросов помечаются is_test=true.

В sandbox вебхуки delivery.success / delivery.failed диспатчатся с задержкой ~2 секунды — это имитирует реальную асинхронность (боевые вебхуки приходят уже после ответа API).

Ручной триггер событий

POST /v1/test/simulate-event доступен только с тестовым ключом zn_test_. Эндпоинт реально доставляет произвольное событие на webhook-эндпоинты проекта с HMAC-подписью и пометкой is_test=true — удобно отлаживать обработчик любого события без воспроизведения сценария. Тело: event (имя из списка известных событий) и data (произвольный JSON-объект). Невалидное событие или data не-объект → 400. Если у проекта нет webhook-эндпоинтов — ответ dispatched: true, endpoints: 0.

POST /v1/test/simulate-event
Authorization: Bearer zn_test_...
{
"event": "subscription.created",
"data": { "subscriber_id": "550e8400-...", "channel": "telegram" }
}
→ {
"dispatched": true,
"event": "subscription.created",
"endpoints": 1
}

Тестовый ключ для старого проекта

Проекты, созданные до появления sandbox, не имеют тестового ключа. Сгенерируйте его кнопкой в кабинете: настройки проекта → блок «Тестовый ключ». То же делает запрос POST /api/projects/{id}/test-key — он создаёт ключ либо перевыпускает существующий (повторный вызов ротирует ключ). Ответ содержит test_api_key — он показывается один раз, сохраните его сразу.

POST /api/projects/{id}/test-key
→ { "test_api_key": "zn_test_..." }

Связанные разделы