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

Быстрый старт

Три шага до первого уведомления.

1

1. Создайте проект

Зарегистрируйтесь через Яндекс или ВК, создайте проект в дашборде.

2

2. Получите API-ключ

В настройках проекта скопируйте API-ключ формата zn_aBcDeFgH...

3

3. Отправьте первый запрос

Используйте curl или любой HTTP-клиент:

curl -X POST https://api.zapnoty.com/v1/send
-H "Authorization: Bearer zn_aBcDeFgH..."
-H "Content-Type: application/json"
-d '{
"user_ref": "user_123",
"text": "Привет!"
}'

Аутентификация

Все запросы к API требуют Bearer-токен в заголовке Authorization.

Формат заголовка:

Authorization: Bearer zn_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456

API-ключ имеет формат zn_ + 32 символа. Ключ создаётся в дашборде проекта.

Не передавайте ключ в URL или query-параметрах. Используйте только заголовок Authorization.

POST /v1/send

Отправка персонального уведомления конкретному подписчику по user_ref.

Параметры

user_ref string обязательный

Идентификатор подписчика в вашей системе

text string обязательный

Текст сообщения (до 4096 символов)

format string

Формат текста: plain (по умолчанию), markdown или html

media object

Объект медиа: {type, url}. Типы: photo, video, document

buttons array

Массив рядов кнопок: [[{text, url}]] или [[{text, callback_data}]]

template string

Slug шаблона вместо text

vars object

Переменные для шаблона: {key: value}

Пример запроса

POST /v1/send
 
{
"user_ref": "user_123",
"text": "Заказ #1042 отправлен!",
"format": "markdown",
"buttons": [[{
"text": "Отследить",
"url": "https://example.com/track/1042"
}]]
}

Ответ

{
"ok": true,
"message_id": "msg_abc123"
}

OTP (одноразовые коды)

Отправка и проверка кодов подтверждения через мессенджер.

POST /v1/otp/send

Генерирует 6-значный код и отправляет подписчику.

user_ref string обязательный

Идентификатор подписчика

POST /v1/otp/send
 
{
"user_ref": "user_123"
}

POST /v1/otp/verify

Проверяет введённый код.

user_ref string обязательный

Идентификатор подписчика

code string обязательный

6-значный код от пользователя

POST /v1/otp/verify
 
{
"user_ref": "user_123",
"code": "482916"
}

Лимиты OTP: макс. 5 попыток проверки, TTL кода — 5 минут, 1 активный код на user_ref.

Broadcast (массовая рассылка)

Отправка сообщения всем подписчикам или сегменту.

POST /v1/broadcast

Создаёт задачу рассылки. Сообщения отправляются через очередь.

text string обязательный

Текст сообщения

permission string

Опционально: фильтр по permission

tags array

Опционально: фильтр по тегам ["vip", "beta"]

POST /v1/broadcast
 
{
"text": "Версия 2.0 доступна!",
"permission": "updates",
"tags": ["beta"]
}

GET /v1/broadcast/:job_id

Получение статуса рассылки.

Поля ответа: status (pending/processing/completed/failed), total, sent, failed.

{
"job_id": "b7f3...",
"status": "completed",
"total": 2847,
"sent": 2835,
"failed": 12
}

Подписчики

Управление списком подписчиков и их тегами.

GET /v1/subscribers

Список подписчиков проекта. Поддерживает пагинацию: ?page=1&per_page=50.

PUT /v1/subscribers/:id/tags

Обновление тегов подписчика. Передайте полный массив тегов.

PUT /v1/subscribers/sub_abc/tags
 
{
"tags": ["vip", "beta"]
}

Шаблоны

Шаблоны позволяют переиспользовать текст с переменными. Создаются в дашборде.

Использование: передайте template и vars вместо text в /v1/send.

Переменные в шаблоне обозначаются {{имя}}. Например: «Заказ {{order_id}} доставлен».

Пример

POST /v1/send
 
{
"user_ref": "user_123",
"template": "order_delivered",
"vars": {
"order_id": "1042",
"customer": "Иван"
}
}

Медиа и кнопки

К уведомлениям можно прикрепить медиа-файлы и inline-кнопки.

Типы медиа: photo, video, document. Передайте URL файла.

Кнопки — двумерный массив: внешний массив — ряды, внутренний — кнопки в ряду.

  • Кнопка с URL: {"text": "Открыть", "url": "https://..."}
  • Кнопка с callback: {"text": "Да", "callback_data": "confirm_123"}

Пример с медиа и кнопками

POST /v1/send
 
{
"user_ref": "user_123",
"text": "Ваш заказ готов",
"media": {
"type": "photo",
"url": "https://example.com/photo.jpg"
},
"buttons": [[
{"text": "Подробнее", "url": "https://..."},
{"text": "Отмена", "callback_data": "cancel_123"}
]]
}

Вебхуки

Zapnoty отправляет HTTP POST на ваш URL при наступлении событий.

События: subscriber.new, subscriber.stop, message.delivered, message.failed, otp.verified.

Подпись: заголовок X-Zapnoty-Signature содержит HMAC-SHA256 от тела запроса с вашим webhook secret.

Проверка подписи:

// Node.js
const crypto = require('crypto');
 
const signature = req.headers['x-zapnoty-signature'];
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(JSON.stringify(req.body))
.digest('hex');
 
if (signature !== expected) // отклонить запрос

Формат payload:

{
"event": "subscriber.new",
"timestamp": "2026-03-05T12:00:00Z",
"data": {
"subscriber_id": "sub_abc",
"user_ref": "user_123",
"channel": "telegram"
}
}

Лимиты

Rate limits и ограничения на размеры полей.

Rate limit: 300 запросов/мин на проект. При превышении — 429 Too Many Requests.

Текст сообщения: до 4 096 символов.

Кнопки: до 3 рядов, до 3 кнопок в ряду.

Медиа: до 20 МБ (photo), 50 МБ (video/document).

Broadcast: до 100 000 подписчиков за одну рассылку.

OTP: TTL 5 мин, макс. 5 попыток, 1 активный код на user_ref.

Теги: до 20 тегов на подписчика, длина тега до 64 символов.

Коды ошибок

API возвращает стандартные HTTP-коды с JSON-телом ошибки.

Формат ошибки:

{
"error": {
"code": "VALIDATION_ERROR",
"message": "text is required"
}
}

400 — Невалидный запрос (отсутствуют обязательные поля, неверный формат)

401 — Неверный или отсутствующий API-ключ

403 — Нет доступа к ресурсу

404 — Подписчик или ресурс не найден

409 — Конфликт (например, OTP уже отправлен)

422 — Ошибка валидации (текст слишком длинный, невалидный URL)

429 — Превышен rate limit

500 — Внутренняя ошибка сервера

Playground

Соберите запрос к API и скопируйте готовую curl-команду.

Тело запроса
{
  "user_ref": "user_123",
  "text": "Привет от Zapnoty!"
}
curl-команда
curl -X POST https://api.zapnoty.com/v1/send \
  -H "Authorization: Bearer zn_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "user_ref": "user_123",
  "text": "Привет от Zapnoty!"
}'