События описывают, что произошло в сети; каналы определяют, куда уйдёт оповещение. Подписка выбирает подходящую активность, ждёт выполнения условия отправки (trigger) и отправляет уведомление через привязанный к ней канал. Доступны два вида, и у них общий жизненный цикл.
Webhook + Telegram Подписанные доставки Единый жизненный цикл История уведомлений
Для создания, изменения и проверки каналов нужен ключ проекта с api:channel:write, для удаления - api:channel:delete, для чтения каналов и истории - api:channel:read. На каждое изменение сохраняйте отдельный Idempotency-Key и исходные входные данные; после потери ответа повторяйте их без изменений. См. Идемпотентность.
Webhook - HTTP-уведомление: Vilna отправляет JSON на ваш обработчик для автоматической обработки; канал Telegram шлёт форматированное сообщение в чат для людей. В продакшене обычно работают оба - один действует, другой наблюдает.
HTTP POST с телом WebhookV2Payload и подписью для проверки подлинности.
HTTP POST на ваш эндпоинт
JSON (WebhookV2Payload)
Автоматические системы и бэкенды
URL + опциональные заголовки
Форматированное сообщение бота в группе, канале или личке - читается с одного взгляда.
Сообщение бота в чат
Форматированный текст
Мониторинг и оповещение людей
Токен бота + chat_id
Webhook-канал отправляет HTTP POST с JSON-телом на ваш эндпоинт, когда выполняется условие привязанной подписки. Создайте его через POST /channels.
В конфигурации выберите kind: webhook, задайте URL получателя и при необходимости отдельные заголовки. Явно выберите payload_version: v2 для структурированных событий; версия тела уведомления выбирается независимо от версии HTTP API. Схемы запроса, ответа и примеры на языках доступны на странице создания канала выше.
Заголовки хранятся и возвращаются без маскировки читателям канала с доступом. Если получателю нужна аутентификация, используйте отдельные учётные данные получателя и ограничьте чтение канала. Не помещайте туда API-ключ Vilna. Также проверяйте webhook-подпись.
Сохраните webhook_secret из ответа создания в менеджере секретов. Повтор создания с тем же ключом и телом может восстановить его в течение 60 секунд после завершения, при текущем доступе и только пока секрет текущий. Повторы не продлевают окно; поздний GET возвращает метаданные, а не открытый секрет. При потере секрета восстановите или явно смените его. Им проверяют X-Webhook-Signature; учётные данные получателя и токен бота Telegram отличаются от API-ключа Vilna.
Webhook - это обычный HTTP POST, поэтому один канал может разветвиться куда нужно вашей архитектуре. Направьте URL на тонкий прокси и раздавайте оттуда:
сохранение исходного тела уведомления
SQS, RabbitMQ, Pub/Sub
оповещения для людей
эскалация крупных событий
любой HTTP-эндпоинт
По конкретной интеграции пишите на support@vilna.io.
Telegram-канал шлёт форматированные сообщения в чат через Bot API. Сначала настройте бота, затем создайте канал:
Создайте бота через @BotFather и сохраните токен бота.
Добавьте бота в нужный чат - группу, канал или личные сообщения.
Получите chat ID через @userinfobot или Telegram API getUpdates.
Создайте канал через Создание канала с kind: telegram, токеном бота и chat_id. Выберите язык сообщений; для темы форума задайте thread_id, иначе оставьте 0. Схема конфигурации и примеры запросов находятся на странице операции.
Оба вида проходят один и тот же цикл из пяти шагов. Отличается только config - эндпоинты одинаковы.
С ключом, имеющим api:subscription:write, создайте подписку на этот канал. Она определяет, какие транзакции вызывают уведомления.
max_attempts (1-10) ограничивает автоматические попытки доставки одного уведомления, считая первую. Неудачные попытки повторяются по фиксированному расписанию с растущей задержкой; десять попыток растягиваются примерно на сутки. Когда бюджет исчерпан, канал отключается с disabled_reason: attempts_exhausted. Адресат, чью непригодность сервис подтвердил, отключает канал сразу с channel_error. Переключателя «держать канал включённым несмотря ни на что» нет; настройка - это бюджет попыток.
Отключение канала, автоматическое или ручное, отменяет все уведомления, которые его ещё ждали: они завершаются со status: canceled и reason: channel_disabled. Повторное включение принимает только новые транзакции, а не отменённый остаток. Ручная повторная отправка и тест в бюджет не входят.
Поднять бюджет можно через PATCH /channels/{channel_id}. Ни повышение бюджета, ни починка адресата сами по себе отключённый канал не включают; is_enabled задаётся явно, можно в том же запросе.
Чтобы обнаружить отключение канала, опрашивайте GET /channels и следите за is_enabled: false, либо запрашивайте GET /notifications со status=canceled и идентификатором канала, чтобы увидеть, что было отменено и почему.
Изменение URL или заголовков вебхука либо чата Telegram отменяет автоматические повторы доставок, у которых уже была хотя бы одна попытка; ротация секрета подписи вебхука на это не влияет.
Отключённый канал не теряет депозит. Транзакция, строки активности и баланс записываются независимо от того, ушло ли уведомление; отменяется только доставка. Три привычки сводят разрыв к минимуму:
Поставьте max_attempts: 10 на каналы мониторинга платежей. Это примерно сутки автоматических повторов, прежде чем канал сдастся.
Создайте вторую подписку с теми же фильтрами на второй канал, например чат Telegram или ещё один вебхук. Подписка привязана к одному каналу, поэтому отключение одного не мешает второму доставлять.
После включения сверьте отменённые уведомления и движения средств за время простоя.
Для сверки требуется api:activity:read:
- Получите
chain_gidиtxidотменённых уведомлений черезGET /notifications?status=canceled&channel_id=…. Соберите все страницыGET /activityсdate_fromиdate_toза время простоя. - Повторите отправку уведомлений, чьё тело ещё хранится; см. ответы повторной отправки. При
notification.payload_unavailableсверяйте саму транзакцию. Приnotification.send_in_progressдождитесь уже поставленной в очередь или выполняющейся попытки. - Группируйте все строки активности по
chain_gid,txid(hashприpayload_version: v1),addressиasset_gidи суммируйте знаковыеdelta.base, учитывая входящие и исходящие эффекты. Несколько выходов Bitcoin на один адрес относятся к одной группе. Затем примените собственные правила допустимости депозита и подтверждений; сумму всех входящих строк нельзя автоматически считать начислением. Сохраните ключ группы и результат учёта атомарно.
event_id определяет уведомление, а не перевод: другая подписка может сообщить о том же депозите с другим event_id. Используйте его для отсеивания повторных доставок одного уведомления, а общий ключ начисления - для сверки между подписками и опросом API.
После создания используйте Проверка канала. Укажите только семейство транзакции, например evm; выбрать транзакцию, получателя или вид события нельзя. Схему запроса и примеры см. на странице операции.
Ответ - 202 с notification_id. Тест работает и на отключённом канале, состояние канала не меняет; он шлёт один встроенный пример для указанного семейства, без живых данных, за одну попытку без автоповторов. Тест, который не ушёл за пять минут, завершается с причиной test_expired. Проверьте уведомление, затем явно начните новый тест с новым ключом идемпотентности; повтор старого ключа лишь вернёт сохранённый ответ принятия.
Каждое уведомление и каждая попытка его доставки сохраняются в истории. По ней можно убедиться, что тест дошёл, и разобрать сбои. Список уведомлений отдаёт GET /notifications, сначала самые свежие, а GET /notifications/{notification_id}/logs показывает все попытки по одному из них.
Начните с фильтров channel_id и status; отделяйте тесты через is_test, а период задавайте через date_from и date_to. Для поиска по txid также нужен chain_gid. Прочитайте все страницы результата. Полный набор фильтров, схемы ответов и примеры запросов приведены на странице списка уведомлений выше.
У каждой попытки в логе есть HTTP-статус и ошибка, которые вернул ваш эндпоинт. Когда оповещения перестали приходить, запросите status=failed и посмотрите последнюю попытку.
После исправления эндпоинта используйте POST /notifications/{notification_id}/actions/resend. Для новой ручной отправки задайте отдельный Idempotency-Key; при потере ответа повторяйте с ним же.
| Ответ | Что делать |
|---|---|
202 | Отправка поставлена в очередь с тем же телом и event_id; отсеивайте повторные доставки по event_id. |
429 notification.resend_delayed | Дождитесь Retry-After для паузы между попытками доставки. |
409 notification.send_in_progress | Дождитесь текущей попытки. |
409 notification.payload_unavailable | Сверяйте саму транзакцию. |
Повторная отправка использует текущего адресата, заголовки и данные подписи канала. Сохранённое тело не сохраняет старую конфигурацию и не обновляет факты о транзакции. Перечитайте счёт, прежде чем считать повторную отправку признаком завершения. Тело хранится 30 дней после завершения уведомления; затем повторная отправка недоступна.
Требования к получателю, включая проверку подписи, обработку повторов и время ответа, описаны в справочнике Webhooks. Используйте отдельные каналы для окружений и задач, чтобы критичные оповещения не смешивались с рутинными.