Документация
Исходящие вебхуки: структура запроса и подпись
Получайте оповещения и отчёты AutoPSEO в виде подписанного JSON на любой HTTPS-эндпоинт: заголовки запроса, поля тела, типы событий и проверка подписи.
Исходящий вебхук отправляет оповещения AutoPSEO, отчёты по расписанию, тестовые сообщения и сводки отчётов на ваш эндпоинт: каждое сообщение приходит отдельным JSON-запросом POST, подписанным по алгоритму HMAC-SHA256. Используйте его, чтобы передавать данные в Zapier, Make, n8n, систему управления инцидентами или собственный код; аккаунт Slack или Teams при этом не нужен. Ищете вебхук, который доставляет статьи на ваш сайт? Он относится к контент-движку: см. доставку контента.
Как добавить вебхук
- В разделе Outbound webhooks нажмите New webhook.
- Укажите Name и вставьте URL эндпоинта. Адрес должен быть публичным и использовать HTTPS: обычный
http,localhost, имена с окончанием.localили.internal, хосты без точки, а также частные и link-local IP-адреса отклоняются. - Скопируйте signing secret, который появится после сохранения. Он показывается только один раз.
- Нажмите Send test, чтобы отправить событие
test, а затем подключите к вебхуку отчёты по расписанию или оповещения.
Как выглядит запрос вебхука
Каждое сообщение — это POST со следующими заголовками:
| Заголовок | Значение |
|---|---|
Content-Type | application/json |
User-Agent | AutoPSEO-Webhook/1.0 |
X-AutoPSEO-Event | Тип события, например traffic_drop |
X-AutoPSEO-Signature | sha256= и 64 строчных шестнадцатеричных символа |
Ниже показано оповещение о падении трафика для доменного ресурса по запуску в 06:00 UTC 12 октября 2026 года. Оно отформатировано для удобства чтения (в реальном запросе JSON передаётся в компактном виде, а значения id и site_id придуманы):
{
"id": "9b2e61f04c3a4d7e8f15a0b6c2d39e47",
"event_type": "traffic_drop",
"severity": "high",
"site_id": "4f0c1e9a2b7d4c58",
"site_url": "sc-domain:example.com",
"occurred_at": "2026-10-12T06:00:04.183Z",
"title": "Traffic drop: example.com",
"text": "Clicks 1,500 vs 2,000 in the previous window (-25.0%).",
"url": "https://app.autopseo.com/property/sc-domain%3Aexample.com",
"payload": {
"fields": [
{ "label": "Metric", "value": "clicks" },
{ "label": "Current", "value": "1,500" },
{ "label": "Baseline", "value": "2,000" },
{ "label": "Window", "value": "7 days (2026-10-05 → 2026-10-11 vs 2026-09-28 → 2026-10-04)" },
{ "label": "Change", "value": "-25.0%" }
],
"table": null,
"detector": "traffic_drop",
"window": 7,
"range": { "start": "2026-10-05", "end": "2026-10-11", "compStart": "2026-09-28", "compEnd": "2026-10-04" },
"result": {
"fired": true,
"metric": "clicks",
"value": 1500,
"baseline": 2000,
"change": -0.25,
"severity": "high",
"summary": "Clicks 1,500 vs 2,000 in the previous window (-25.0%)."
}
},
"source": "autopseo"
}
Поля верхнего уровня одинаковы для всех событий:
| Поле | Что содержит |
|---|---|
id | Случайная строка из 32 шестнадцатеричных символов, новая для каждого запроса |
event_type | Что произошло (см. следующий раздел) |
severity | critical, high, medium или low для оповещений; info для отчётов, сводок и тестов |
site_id | Идентификатор ресурса в AutoPSEO или null для тестов и демонстрационного ресурса |
site_url | Ресурс Search Console, например sc-domain:example.com или https://www.example.com/, либо null для тестов |
occurred_at | Время формирования сообщения в формате ISO 8601 (UTC) |
title, text | Заголовок и краткое описание, которые показывают Slack и Teams |
url | Ссылка на отчёт в AutoPSEO или null для тестов |
payload.fields | Именованные значения: Slack показывает их как поля, а Teams — как факты |
payload.table | columns и rows для отчётов и сводок, в остальных случаях null |
source | Всегда autopseo |
Относительные величины передаются долями: change, равный -0.25, означает падение на 25%, а ctr, равный 0.034, — 3,4%.
Типы событий
event_type | Когда отправляется | Дополнительные ключи в payload |
|---|---|---|
traffic_drop, traffic_spike, position_drop, ctr_drop, new_lost_rankings, anomaly, index_flip, rank_drop, audit_regression | Срабатывает правило оповещения — по расписанию или через Test rule | detector, window, range (даты или null для index_flip, rank_drop и audit_regression), result |
scheduled_report | Отправляется отчёт по расписанию — по расписанию или через Send now | reportType (summary, queries, pages или rankings), range (даты и label), totals, previous |
report_summary | Кто-то нажимает Send to Slack на странице отчёта | Нет: показатели находятся в fields и table |
test | Кто-то нажимает Send test у вебхука | sample, всегда true |
В result повторяется то, что измерил детектор: fired, metric, value, baseline, change (null, если сравнивать не с чем), severity и summary, а для anomaly ещё и z — модифицированная z-оценка. В totals и previous находятся clicks, impressions, ctr и position для двух периодов отчёта. Что именно измеряет каждый детектор, описано в разделе Оповещения.
Как проверить подпись
Подпись — это HMAC-SHA256 от точных байтов, отправленных AutoPSEO, с использованием signing secret вебхука в качестве ключа; она записывается как sha256= и строчный hex. Для проверки:
- Прочитайте необработанное тело запроса до любого разбора JSON. Повторный разбор и сериализация могут изменить байты.
- Вычислите HMAC-SHA256 от этих байтов, используя секрет как текст: 64-символьную строку ровно в том виде, в каком она показана, без декодирования из hex.
- Добавьте префикс
sha256=и сравните результат с заголовкомX-AutoPSEO-Signatureза постоянное время. - Если значения не совпадают, отклоните запрос. Иначе сразу ответьте статусом 2xx, а долгую обработку выполните позже.
Приёмник для Node.js без зависимостей:
import { createServer } from 'node:http';
import { createHmac, timingSafeEqual } from 'node:crypto';
const secret = process.env.AUTOPSEO_WEBHOOK_SECRET;
createServer((req, res) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const raw = Buffer.concat(chunks);
const expected = Buffer.from('sha256=' + createHmac('sha256', secret).update(raw).digest('hex'));
const received = Buffer.from(String(req.headers['x-autopseo-signature'] || ''));
if (received.length !== expected.length || !timingSafeEqual(received, expected)) {
res.writeHead(401).end();
return;
}
res.writeHead(204).end();
const event = JSON.parse(raw.toString('utf8'));
console.log(event.event_type, event.severity, event.site_url);
});
}).listen(8080);
Проверка длины идёт первой, потому что timingSafeEqual в Node выбрасывает исключение, если длины буферов различаются.
Правила доставки
- На каждое сообщение делается одна попытка с таймаутом 10 секунд. Любой ответ, кроме 2xx, считается неудачей и сохраняется в Delivery history вместе с кодом статуса и началом тела вашего ответа.
- Перенаправления не выполняются. Ответ 3xx считается неудачей, и в примечании предлагается использовать конечный URL.
- По таймеру ничего не повторяется. Неудачное оповещение не помечается как отправленное, поэтому при следующей проверке оно будет оценено снова и отправлено, если условие всё ещё выполняется: на следующее утро для большинства детекторов и через час для index flip. Неудачный отчёт по расписанию в том же периоде повторно не отправляется, поэтому после исправления эндпоинта воспользуйтесь Send now.
idсоздаётся для каждого запроса, поэтому он идентифицирует доставку, а не событие. Чтобы убрать дубликаты оповещений, объединитеevent_type,site_urlи дату изoccurred_at: правило отправляет оповещение не чаще одного раза в сутки (UTC) на ресурс, если только кто-то не запустил Test rule.
Signing secret
AutoPSEO показывает signing secret один раз, при сохранении вебхука, а в списке он больше не отображается. Сразу сохраните его в конфигурации вашего приёмника рядом с эндпоинтом, который он защищает.
Сам URL хранится в зашифрованном виде, а в списке отображаются только его хост и последние символы. Удаление вебхука также удаляет все правила, которые отправляют сообщения на него. Если вместо JSON нужна читаемая карточка в канале Teams, воспользуйтесь Microsoft Teams.