Вебхуки
Подписка на события платформы и проверка подписи доставки.
LegalStack доставляет события платформы на ваши HTTPS-эндпоинты. Подписками управляют через раздел API «Безопасность и доступ» — вебхуки, нужен scope webhooks:write.
Регистрация эндпоинта
POST /api/v1/webhooks HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{ "url": "https://example.com/hooks/legalstack", "events": ["task.created", "signature.signed"] }В ответе придёт секрет эндпоинта с префиксом whsec_ — он нужен для проверки подписи. Все операции с подписками — в справочнике API.
Секрет показывается один раз
Сохраните секрет сразу после создания эндпоинта. Платформа хранит его зашифрованным и повторно не покажет, можно только сгенерировать новый.
Доставка
Каждое событие приходит POST-запросом с JSON-телом { id, type, teamId, timestamp, data } и четырьмя заголовками:
| Заголовок | Значение |
|---|---|
x-legalstack-signature | подпись v1=<hex> |
x-legalstack-timestamp | unix-время отправки в секундах |
x-legalstack-event-id | идентификатор события |
x-legalstack-event-type | тип события |
Пример реальной доставки (подпись вычислена боевым кодом платформы):
POST /ваш-endpoint HTTP/1.1
content-type: application/json
x-legalstack-signature: v1=29e7075a454efa9d2fdb5b5d15e1e4e93bfd2b635717bda86931b63566f71c16
x-legalstack-timestamp: 1752307200
x-legalstack-event-id: evt_01hzxamp1e
x-legalstack-event-type: task.created
{"id":"evt_01hzxamp1e","type":"task.created","teamId":"team_01hzxamp1e","timestamp":"2026-07-12T08:00:00.000Z","data":{"taskId":"task_01hzxamp1e","teamId":"team_01hzxamp1e","data":{"title":"Проверить договор"}}}
Проверка подписи
Подпись — HMAC-SHA256 в hex от строки timestamp + "." + payload, ключ — секрет эндпоинта как обычная UTF-8-строка (без декодирования):
secret = "whsec_2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c"
timestamp = "1752307200" // значение заголовка x-legalstack-timestamp
payload = тело запроса (сырые байты)
signature = "v1=" + hex(hmac_sha256(secret, timestamp + "." + payload))
= "v1=29e7075a454efa9d2fdb5b5d15e1e4e93bfd2b635717bda86931b63566f71c16"
Сравнивайте подписи константным по времени сравнением и отклоняйте доставки со старым timestamp (например, старше 5 минут) для защиты от replay.
Повторные доставки
Неуспешные доставки (не-2xx ответ) повторяются с экспоненциальной задержкой. Обрабатывайте события идемпотентно по x-legalstack-event-id — одно событие может прийти более одного раза.
Каталог всех типов событий — на странице События вебхуков.
Вебхук формы
Форма может сама отправлять каждый ответ на ваш сервер. Включите Webhook на вкладке «Каналы» конструктора формы и укажите адрес, который начинается с https://. Секрет для подписи создаётся автоматически. Он хранится зашифрованным отдельно от настроек формы, поэтому его не видят те, кто может только просматривать форму.
В меню рядом с кнопкой «Проверить» пункт «Копировать секрет» получает действующий секрет с сервера, а «Перевыпустить секрет» выпускает новый: прежний перестаёт подходить сразу. То же доступно через API: GET /api/v1/interfaces/{id}/webhook/secret возвращает секрет, POST по тому же адресу перевыпускает его. Нужно право редактировать форму и scope interfaces:write.
Ответ приходит POST-запросом с теми же заголовками и той же подписью v1, что и события платформы. Тип события interface.submitted, а x-legalstack-event-id совпадает с submissionId ответа.
{
"event": "interface.submitted",
"interfaceId": "6f1c2e84-3b7a-4d0e-9c51-2a7f0b9e1d43",
"submissionId": "a93e07c4-58d2-4f1b-b6e0-7c3d9a1f2e85",
"data": {
"_interfaceId": "6f1c2e84-3b7a-4d0e-9c51-2a7f0b9e1d43",
"_source": "web",
"_submittedAt": "2026-10-06T12:00:00.000Z",
"_ipAddress": "203.0.113.24",
"_userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"licensee_name": "Иванов Иван Иванович",
"licensee_email": "ivanov@example.ru"
},
"channel": "web",
"submittedAt": "2026-10-06T12:00:00.000Z"
}В data лежат ответы по ключам полей формы и служебные значения с префиксом _: канал, из которого пришёл ответ (web, embed, telegram или api), время отправки, IP-адрес и User-Agent отправителя. Для ответов из Telegram добавляется _telegramUserId. Поле channel повторяет _source.
Кнопка «Проверить» отправляет на адрес тестовый ответ с полем "test": true и показывает код и время ответа вашего сервера. Если сервер ответил не 2xx, доставка повторяется с нарастающей задержкой, каждый раз с текущими адресом и секретом формы. Если выключить вебхук, недоставленные ответы больше не отправляются.
Секрет, заданный вручную
Если секрет вебхука формы вводили вручную, подпись остаётся в прежнем формате: HMAC-SHA256 в hex от тела запроса, без v1= и без timestamp. Перевыпустите секрет, чтобы перейти на общий формат подписи.