Webhooks¶
Отправляйте события жизненного цикла сессий из Expecto на ваш URL в момент, когда они происходят. Webhooks подходят, чтобы запускать последующие BI- конвейеры, кидать оповещения в Slack/Teams при упавшей сессии или передавать экспортированный пакет в свои системы без постоянного опроса.
Что нужно
Роль owner или admin в организации. Каждый endpoint принадлежит одной организации и, опционально, одному проекту в ней.
Что доставляется¶
Для каждой сессии в организации Expecto эмитит webhook на каждом переходе жизненного цикла:
| Событие | Когда срабатывает |
|---|---|
session.created |
Создана новая сессия |
session.uploaded |
Загружен файл для сессии |
session.parsed |
Парсинг завершён без ошибок |
session.transformed |
Трансформация завершена без ошибок |
session.checked |
Бизнес-правила прошли без ошибок |
session.confirmed |
Отправитель подтвердил данные |
session.approved |
Финальная апрува дана (только в режиме dual — single пропускает этот шаг) |
session.exported |
Экспортный пакет сгенерирован и загружен |
session.failed |
Упала стадия пайплайна (parse, transform или check). В payload — stage и reason. |
webhook.ping |
Синтетическое тестовое событие по запросу |
Payload не содержит download URL для экспортного пакета — потребители
скачивают его авторизованно через API со своим API key. Событие экспорта
несёт имя пакета и список артефактов с sha256, row_count и
size_bytes для каждого файла.
Где найти¶
Открой Settings → Webhooks. Вкладка показывает все видимые endpoint'ы и кнопку Create Webhook.

Создание endpoint'а¶
Нажми Create Webhook. В диалоге три поля:
- Name — человекочитаемое название, чтобы различать endpoint'ы в списке и в логе доставок.
- URL — куда Expecto будет POST'ить события. Только
https://. Приватные, loopback, link-local и cloud-metadata IP-диапазоны отвергаются на этапе создания (SSRF-защита). Dev-override (webhook_allow_http) доступен только операторам инстанса Expecto, не в UI. - Event types — минимум одно. События сгруппированы по неймспейсу
(напр.
session.*) в дерево: отмечай отдельные события, переключай всю группу её чекбоксом или используй Select all / Clear. Выбор можно поменять позже через Edit.

После Create Expecto покажет подписной ключ ровно один раз в
модалке. Скопируй его сейчас — это единственный момент, когда виден ключ
в открытом виде. Expecto хранит зашифрованную форму и после этого показывает
только префикс whsec_…. Если потеряешь — ротируй ключ и обнови
потребителя.
Список endpoint'ов¶
Каждая строка показывает URL, подписанные события, префикс ключа и badges состояния:
- Disabled — endpoint на паузе; новые события не доставляются.
- Auto-disabled — Expecto отключил endpoint после 10 подряд dead-letter доставок (см. Обработка ошибок).

Outbound-биндинги в том же списке¶
Кроме webhook-endpoint'ов список показывает outbound-биндинги
организации — правила уровня проекта, которые пишут события сессий прямо во
внешнюю платформу через интеграционное подключение (сегодня — Salesforce).
Карточка биндинга несёт бейдж Outbound binding и тип адаптера, вместо URL
показывает подключение → цель (объект Salesforce), подписанные события,
проект-владелец и один из бейджей состояния:
- Active — события доставляются.
- Inactive — биндинг на паузе.
- Auto-disabled — Expecto поставил биндинг на паузу после серии dead-letter-доставок подряд; счётчик показан рядом с бейджем.
Биндинги редактируются в проекте, а не здесь: открой Project › Context › Outbound Bindings (действие Open in project ведёт туда). Show deliveries на карточке открывает тот же лог доставок, что и у endpoint'ов; колонка Result заполняется из ответа внешней системы.
Меню Actions¶
У каждой карточки endpoint'а справа есть меню Actions ▾. Пункты:

- Edit — изменить имя, URL, подписанные события или кастомный auth-заголовок endpoint'а. Открывает диалог, предзаполненный текущими значениями.
- Show deliveries / Hide deliveries — разворачивает таблицу лога доставок inline (см. ниже).
- Send ping — отправляет синтетическое
webhook.pingenvelope на endpoint. Используй после создания endpoint'а, чтобы убедиться, что потребитель достижим и корректно проверяет подпись. - Rotate secret — генерирует новый подписной ключ, шифрует и сохраняет, показывает его в открытом виде ровно один раз в той же reveal-one модалке. Предыдущий ключ перестаёт приниматься в момент подтверждения ротации — обновляй потребителя в один шаг, иначе будут ошибки проверки подписи.
- Disable / Enable — пауза/возобновление доставок. Пауза не удаляет endpoint и историю; ожидающие ретраи просто останавливаются.
- Delete — удаляет endpoint и историю доставок. Необратимо.
Лог доставок¶
Выбери Show deliveries, чтобы увидеть последние 50 доставок к endpoint'у, начиная с самой свежей.

Колонки:
- Event — тип события (например
session.exported,webhook.ping). - Status —
pending,in_progress,succeededилиfailed. - Attempts — текущая попытка из максимума (по умолчанию
6). - Code — последний HTTP-статус, который вернул твой endpoint.
- Result — что вернулось: для успешной доставки outbound-биндинга — id записи, созданной во внешней системе (например, id записи Salesforce), для неудачной — фрагмент ошибки (полный текст по наведению), для ожидающего ретрая — время следующей попытки.
- When — время последней попытки.
- Actions — кнопка Replay (см. ниже).
Replay доставки¶
Replay переотправляет тот же payload, но генерирует новый
webhook-id и перепподписывает body, чтобы проверка подписи всё ещё
прошла. Используй, если потребитель пропустил доставку или нужно
переслать что-то, что попало в failed после починки приёмника. Новая
доставка связана с оригиналом — твоя целевая система может
дедуплицировать по исходному event id, если нужна exactly-once
семантика, или обрабатывать replay как свежее событие.
Обработка ошибок¶
Если потребитель возвращает что-то вне 2xx, Expecto делает retry с экспоненциальным backoff (по умолчанию: база 30 с, cap 1 ч, 6 попыток всего) и per-delivery jitter, чтобы retry'и с разных endpoint'ов не синхронизировались.
Когда у доставки закончились попытки, она уходит в dead-letter, а
счётчик consecutive_failures endpoint'а увеличивается. После 10
подряд dead-letter доставок endpoint автоматически отключается —
Expecto ставит disabled_reason = "consecutive_failures" и перестаёт
эмитить новые события.
Чтобы вернуть auto-disabled endpoint, почини потребителя и нажми Enable в Actions меню. Счётчик сбрасывается, и Expecto начинает эмитить новые события сразу, как они появляются (события, которые уже ушли в dead-letter, автоматически не реэмитятся — нажми Replay вручную, если нужны).
Одной успешной доставки достаточно, чтобы сбросить счётчик — нестабильный потребитель, который чинится в пределах девяти ошибок, не дотянет до auto-disable.
Скоупинг endpoint'а на проект¶
Endpoint'ы без проекта — org-level: получают каждое подходящее событие сессий организации, независимо от проекта сессии. Endpoint'ы, привязанные к проекту, получают только события сессий этого проекта. Используй project-scope, когда у разных команд разные BI- потребители, или когда контрактору не нужно видеть сессии других проектов.
Project scope ставится программно (через API или MCP) — в текущем UI- диалоге он не открыт. Фильтр в списке endpoint'ов уважает твой проектный доступ — контракторы видят только endpoint'ы своих проектов.
Кастомный auth header¶
Некоторые приёмники стоят за reverse proxy или API Gateway, который
требует от отправителя (нас) авторизоваться — например
Authorization: Bearer <token> против OAuth2-прокси или
X-API-Key: <key> против собственного шлюза. В диалоге создания
поставь галочку Add a custom auth header, чтобы добавить такой
заголовок. Введи имя (например Authorization) и значение (Bearer
eyJ…); значение шифруется тем же Fernet-ключом, что и подписной
секрет, и расшифровывается только в момент отправки запроса.
Значение заголовка — write-only: после сохранения UI показывает только имя, но не значение. Чтобы ротировать значение, открой endpoint на редактирование и введи новое; чтобы полностью убрать заголовок — через API (UI для очистки будет в следующей итерации).
Это дополняет, не заменяет HMAC-подпись. Подпись аутентифицирует отправителя (Expecto). Кастомный заголовок позволяет твоей инфраструктуре решить — принимать ли запрос вообще.
Безопасность и проверка подписи¶
Каждый request на твой URL несёт три заголовка:
webhook-id— UUID этой доставки. Стабилен на retry; меняется на replay.webhook-timestamp— Unix-секунды на момент подписания.webhook-signature—v1,<base64-HMAC-SHA256>отwebhook-id.timestamp.body.
Проверяй, пересчитывая HMAC с подписным ключом endpoint'а и сравнивая
constant-time. Отвергай request старше 5 минут
(webhook_signature_tolerance_seconds).
Примеры проверки на Python и Node и полное описание envelope — в референсе разработчика For Developers → Webhooks.