Skip to content
Язык: Русский

API для разработчиков

Вебхуки: события, payload и подпись

Обновлено 1 ноября 2026 г. 6 мин чтения

Настройте вебхуки в панели управления, принимайте доставки и проверяйте HMAC-подпись — с примерами для curl, Node.js и PHP.

Вебхук отправляет HTTP-запрос на ваш сервер, как только в вашем рабочем пространстве что-то происходит, — например, когда страница опубликована. Так вам не нужно постоянно спрашивать, изменилось ли что-нибудь. Каждая доставка подписана, чтобы ваш сервер мог отличить настоящие сообщения от поддельных.

Требования

  • Роль владельца или админа в рабочем пространстве — пункт меню «Вебхуки» виден только этим ролям
  • Начиная с Creator Pro; в Creator Free написано «Вебхуки доступны начиная с Creator Pro.»
  • До 5 вебхуков в Creator Pro, 25 в Creator Agency, 100 в Enterprise (настраивается)
  • Сервер, доступный по публичному https-адресу

Вебхуками вы управляете только в панели управления. С API-ключами их нельзя создать или изменить.

Создание вебхука

Страница «Вебхуки» без вебхуков с кнопкой «+ Новый вебхук»
Страница «Вебхуки» в рабочем пространстве
  1. Откройте в навигации «Вебхуки»
  2. Нажмите «+ Новый вебхук»
  3. Введите целевой URL и выберите события
  4. Необязательно: введите описание и выберите статус
  5. Нажмите «Создать вебхук»
  6. На шаге «Готово» скопируйте секрет подписи («Секрет подписи — виден только сейчас») и сохраните его на своём сервере — он показывается только сейчас
  7. Проверьте вебхук кнопкой «Тест». Результат остаётся на карточке до следующего теста: «Успешно доставлено» или «Не доставлено» с HTTP-кодом (или «нет ответа»), длительностью и началом ответа
«Целевой URL (https://…)»
До 2048 символов. Только https, без учётных данных в URL, без адресов localhost и без внутренних имён вроде .local, .internal или .lan. Имя должно указывать на публичные IP-адреса; LinkHarbor проверяет это заново перед каждой доставкой.
«События»
Хотя бы одно событие. В каждой группе есть «Выбрать все» и «Снять выделение».
«Описание»
Необязательно, до 255 символов — например, для чего нужен вебхук.
«Статус»
«Активен» или «Отключён». Отключённые вебхуки не получают доставок.

События

СобытиеВ панели управленияКогдаСодержимое data
page.publishedСтраница опубликованаСтраница опубликована — в панели управления, через API или AI-ассистентомpage_id, version, checksum, published_by_user_id (null для API-ключей и AI-ассистентов)
form.submittedФорма отправленаПосетитель отправил форму на одной из ваших страницform_id, form_name, submission_id, page_id, block_id, submitted_at, values (ключ поля → значение), consent (ключ согласия → true/false)
domain.verifiedДомен подтверждёнСобственный домен успешно подтверждёнdomain_id, hostname, verification_method, status
domain.disabledДомен отключёнСобственный домен отключён в панели управления (не при понижении тарифа)domain_id, hostname, status
webhook.test– (кнопка «Тест»)Вы нажимаете «Тест»message (текст на языке аккаунта того, кто запустил тест; не опирайтесь на него)

form.submitted содержит значения ровно в том виде, в каком их отправил посетитель, но никогда не содержит его IP-адрес или браузер. Доставка выполняется в фоне: посетитель её не ждёт, а неудачная доставка не мешает отправке формы.

Структура доставки

LinkHarbor отправляет каждую доставку как POST с телом в JSON и такими заголовками:

ЗаголовокСодержимое
Content-Typeapplication/json
X-LinkHarbor-EventНазвание события, например page.published
X-LinkHarbor-Delivery-IdУникальный ID этой доставки (UUID), совпадает с id в теле
X-LinkHarbor-TimestampВремя отправки в Unix-секундах
X-LinkHarbor-Signaturesha256=, за которым следует подпись HMAC-SHA256 в hex
X-LinkHarbor-Signature-Versionv1
Пример payload для page.published
{
  "id": "3f1c2a9e-8d4b-4a51-9f0e-6b7c1d2e3f40",
  "event": "page.published",
  "created_at": "2026-11-01T09:30:12+00:00",
  "data": {
    "page_id": 42,
    "version": 8,
    "checksum": "9b1e5c…",
    "published_by_user_id": 7
  }
}

Повторные доставки получают новый id, а также поля redelivery_of (ID повторяемой доставки) и delivery_root (ID первой доставки в этой цепочке).

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

У каждого вебхука свой секрет подписи (32 hex-символа). Вы видите его ровно один раз: на последнем шаге при создании вебхука и сразу после «Секрет ↺». Сразу скопируйте его на свой сервер — LinkHarbor больше его не покажет. С его помощью LinkHarbor вычисляет подпись так:

  1. Составляет сообщение: временная метка, точка, ID доставки, точка, исходное тело — то есть timestamp.delivery_id.body
  2. Вычисляет HMAC-SHA256 от этого сообщения с секретом подписи в качестве ключа
  3. Отправляет результат как hex-строку с префиксом sha256=

Ваш сервер должен проверять подпись сравнением за постоянное время, отклонять доставки с временной меткой старше 300 секунд и хранить ID доставок как минимум столько же, чтобы распознавать повторы. Важно: подписывается исходное тело ровно в том виде, в каком оно пришло, — а не JSON, который вы закодировали заново.

Node.js (Express): приём и проверка вебхука
import crypto from 'node:crypto';
import express from 'express';

const app = express();
const SECRET = process.env.LH_WEBHOOK_SECRET;
const seen = new Set(); // в продакшене: база данных или Redis со сроком хранения

app.post('/webhooks/linkharbor', express.raw({ type: 'application/json' }), (req, res) => {
  const ts = req.get('X-LinkHarbor-Timestamp') || '';
  const id = req.get('X-LinkHarbor-Delivery-Id') || '';
  const sig = req.get('X-LinkHarbor-Signature') || '';

  if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
    return res.status(400).send('timestamp');
  }

  const expected = 'sha256=' + crypto
    .createHmac('sha256', SECRET)
    .update(ts + '.' + id + '.')
    .update(req.body) // исходное тело в виде Buffer
    .digest('hex');

  const a = Buffer.from(expected);
  const b = Buffer.from(sig);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send('signature');
  }

  const event = JSON.parse(req.body.toString('utf8'));
  const key = event.delivery_root || event.id; // распознать повторные доставки одной цепочки
  if (!seen.has(key)) {
    seen.add(key);
    // обработать здесь, лучше асинхронно в очереди
  }
  res.sendStatus(200);
});

app.listen(3000);
PHP: приём и проверка вебхука
<?php
$secret = getenv('LH_WEBHOOK_SECRET');
$body   = file_get_contents('php://input');
$ts     = $_SERVER['HTTP_X_LINKHARBOR_TIMESTAMP'] ?? '';
$id     = $_SERVER['HTTP_X_LINKHARBOR_DELIVERY_ID'] ?? '';
$sig    = $_SERVER['HTTP_X_LINKHARBOR_SIGNATURE'] ?? '';

if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) {
    http_response_code(400);
    exit('timestamp');
}

$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $id . '.' . $body, $secret);
if (!hash_equals($expected, $sig)) {
    http_response_code(401);
    exit('signature');
}

$event = json_decode($body, true);
// Распознать повторные доставки по $event['delivery_root'] ?? $event['id'],
// затем обработать.
http_response_code(200);

Проверка эндпоинта с помощью curl

Этот скрипт отправляет на ваш собственный сервер правильно подписанную тестовую доставку — удобно до того, как вы создадите вебхук в LinkHarbor:

Имитация подписанной тестовой доставки
SECRET="your-signing-secret"
URL="https://example.com/webhooks/linkharbor"
TS=$(date +%s)
ID=$(uuidgen | tr 'A-Z' 'a-z')
BODY='{"id":"'"$ID"'","event":"webhook.test","created_at":"2026-11-01T09:30:12+00:00","data":{"message":"Это тестовое событие для этого вебхука."}}'
SIG="sha256=$(printf '%s' "$TS.$ID.$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"

curl -X POST "$URL" \
  -H "Content-Type: application/json" \
  -H "X-LinkHarbor-Event: webhook.test" \
  -H "X-LinkHarbor-Delivery-Id: $ID" \
  -H "X-LinkHarbor-Timestamp: $TS" \
  -H "X-LinkHarbor-Signature: $SIG" \
  -H "X-LinkHarbor-Signature-Version: v1" \
  -d "$BODY"

Ответ, тайм-аут и повторная доставка

  • Любой ответ со статусом 2xx считается успешным; перенаправлениям (3xx) LinkHarbor не следует
  • У вашего сервера есть 10 секунд на ответ и не больше 5 секунд на установку соединения
  • Все вебхуки одного события делят в сумме 25 секунд; те, до которых к этому времени не дошла очередь, помечаются как неудачные и могут быть доставлены повторно
  • LinkHarbor не повторяет неудачные доставки автоматически
  • Неудачные доставки можно отправить повторно вручную, но не ту, которая с тех пор прошла успешно. У повторной доставки новый id и новый created_at
  • На одно событие допускается не больше 3 попыток, включая первую доставку; после этого оно попадает в «Недоставленные» и повторно отправить его уже нельзя

Доставки в панели управления

«Доставки» открывает журнал вебхука. В нём три вкладки:

«Все доставки»
Все доставки с фильтрами по событию, статусу («Успешно (2xx)», «Ошибка клиента (4xx)», «Ошибка сервера (5xx)», «Неудачно») и «Лимит». «↺ Повторить» снова отправляет неудачную доставку, если после неё не было успешной. По клику на строку видны запрос, ответ, тело и исходный JSON.
«Повторы»
Цепочки повторных доставок с результатом «Восстановлено» или «Всё ещё не работает» и числом попыток.
«Недоставленные»
Доставки, у которых все разрешённые попытки не удались, — первая доставка и повторные вместе. Вкладка только для просмотра: повторно доставить их уже нельзя. Проверьте свой эндпоинт; после этого новые события доставляются как обычно. Если данные нужны, получите их через API.

Если повторная доставка не проходит, панель управления называет причину:

«Не доставлено повторно: лимит попыток для этого события исчерпан (неудачных попыток: …). Оно находится в разделе “Недоставленные”.»
Все 3 попытки израсходованы.
«Не доставлено повторно: это событие уже успешно доставлено.»
Более поздняя доставка в той же цепочке уже прошла успешно.

Проверка в панели управления

В разделе «Проверка» есть два вспомогательных инструмента:

«Набор для проверки»
«Загрузить набор» показывает алгоритм, имена заголовков, формат подписываемого сообщения и рекомендуемый допуск в 300 секунд. Самого секрета в наборе нет.
«Проверить подпись»
Введите ID доставки, временную метку, подпись и исходное тело запроса полученной доставки. LinkHarbor ответит «Подпись верна» или «Подпись неверна». Временную метку и подпись скопируйте из заголовков X-LinkHarbor-Timestamp и X-LinkHarbor-Signature. Проверка работает только для доставок за последние 5 минут; для более старых она сообщает «Подпись неверна», даже если подпись правильная.

Перевыпуск секрета, отключение, удаление

  • «Секрет ↺» создаёт новый секрет подписи и показывает его один раз; старый сразу перестаёт действовать, и вашему серверу нужно использовать новый
  • Нажмите «Изменить» и установите статус «Отключён», чтобы приостановить доставки
  • Значок корзины удаляет вебхук; пока вы не закрыли сообщение, удаление можно отменить кнопкой «Отменить»

При переходе на тариф ниже вебхуки сверх нового лимита отключаются, а в Creator Free — все. Они сохраняются; после повышения тарифа LinkHarbor автоматически снова включает отключённые вебхуки в пределах лимита нового тарифа — в том числе те, которые вы отключили сами.

Ничего не нашли?

Напишите, что вам нужно, и наша служба поддержки поможет вам лично.

Написать в поддержку