Встройте мониторинг репутации в свои процессы: уведомления в email, Telegram и Slack, а для автоматизации — типизированные webhook-события с HMAC-подписью (n8n, Albato, SIEM, свой endpoint).
Письма об инцидентах и отчёты. Простой режим — письма с адреса сервиса, свой SMTP — с вашего домена. Доп. получатели верифицируются кодом.
Сервисный бот @postmasterstool_bot или свой бот: личные чаты и группы (включая супергруппы с темами).
Сообщения в канал через Incoming Webhook URL — Block Kit разметка, кнопка «Открыть инцидент».
JSON POST на ваш HTTPS-endpoint: типизированные события v1, HMAC-SHA256 подпись, ретраи. Основа для n8n, Albato, SIEM и своих систем.
Каждая доставка — POST с JSON-конвертом. Поля subject/text/incidentUrl/timestamp сохраняются из первой версии формата; сверху добавлены v, event, occurredAt и (для части событий) data:
{
"v": 1,
"event": "incident.created",
"occurredAt": "2026-07-26T10:15:00.000Z",
"subject": "[CRITICAL] Gmail: вырос spam rate для example.com — INC-2026-000142",
"text": "🔴 CRITICAL — вырос spam rate\nДомен: example.com\n…",
"incidentUrl": "https://postmasterstool.com/incidents/7d2c…",
"timestamp": "2026-07-26T10:15:00.000Z"
}| event | Когда отправляется | data |
|---|---|---|
| incident.created | Новый инцидент или переоткрытие после нарушения правила | — |
| incident.resolved | Инцидент закрыт (автовосстановление по гистерезису) | — |
| incident.reminder | Напоминание по открытому инциденту (кулдаун 6 ч CRITICAL / 24 ч WARNING) | — |
| integration.error | Техническая проблема: сбой подключения, отзыв доступа, сломанный канал | — |
| report.ready | Отчёт по расписанию сформирован и доставлен каналу | scheduleName, periodStart, periodEnd, reportRunId |
| domain.risk_changed | Переход risk-статуса домена green ↔ yellow ↔ red после прогона оценки алертов | domainId, domain, from, to, at |
| billing.event | Биллинговые уведомления (окончание trial, счета) | — |
| test | Тестовое уведомление кнопкой «Проверить» в настройках канала | — |
{
"v": 1,
"event": "report.ready",
"occurredAt": "2026-07-20T09:00:00.000Z",
"data": {
"scheduleName": "Еженедельный",
"periodStart": "2026-07-13",
"periodEnd": "2026-07-20",
"reportRunId": "a41f…"
},
"subject": "Еженедельный отчёт PostmastersTool: 13.07 — 19.07",
"text": "…",
"incidentUrl": null,
"timestamp": "2026-07-20T09:00:00.000Z"
}{
"v": 1,
"event": "domain.risk_changed",
"occurredAt": "2026-07-26T10:20:00.000Z",
"data": {
"domainId": "f5b5…",
"domain": "example.com",
"from": "green",
"to": "yellow",
"at": "2026-07-26T10:20:00.000Z"
},
"subject": "[WARNING] Статус риска домена example.com: green → yellow",
"text": "…",
"incidentUrl": "https://postmasterstool.com/domains/f5b5…",
"timestamp": "2026-07-26T10:20:00.000Z"
}occurredAt — момент наступления события, timestamp — момент отправки. Ретраи при недоступности: через 1 мин, 5 мин, 15 мин, 1 ч и 3 ч (6 попыток всего).
Если в канале задан секрет, тело запроса подписывается HMAC-SHA256, заголовок X-PostmastersTool-Signature: sha256=<hex>. Подписывается сырое тело — проверяйте до парсинга JSON.
const crypto = require('node:crypto');
function verifySignature(rawBody, signature, secret) {
const expected =
'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(signature ?? '', 'utf8');
const b = Buffer.from(expected, 'utf8');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// Express: важно брать СЫРОЕ тело (express.raw), а не распарсенный JSON
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifySignature(req.body, req.get('X-PostmastersTool-Signature'), SECRET)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString('utf8'));
// …обработка event.event / event.data…
res.sendStatus(200);
});import hashlib, hmac, json
from flask import Flask, request
app = Flask(__name__)
SECRET = b'your-webhook-secret'
@app.post('/webhook')
def webhook():
signature = request.headers.get('X-PostmastersTool-Signature', '')
digest = hmac.new(SECRET, request.get_data(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, 'sha256=' + digest):
return 'invalid signature', 401
event = json.loads(request.get_data())
# …обработка event['event'] / event['data']…
return 'ok', 200Триггер Webhook (POST, response «immediately») принимает событие; дальше Switch по полю event и HTTP Request node — в ваш API, Jira или Notion. Проверку подписи можно добавить Code-нодой (пример выше).
Связка с триггером «Входящий webhook»: URL из Albato — в настройки webhook-канала PostmastersTool. Поля event/data доступны в шагах сценария как переменные.
Для Slack обычно достаточно родного канала SLACK (Incoming Webhook URL). Свой Slack App со своей логикой — принимайте generic webhook и шлите в chat.postMessage.
Требования: публичный HTTPS (приватные сети блокируются SSRF-гардом), ответ 2xx быстрее 10 секунд, редиректы не следуются. Делайте обработчик идемпотентным по паре event + occurredAt — ретрай пришлёт то же событие повторно.
Настройки → Уведомления → Новый канал → Webhook. Тестовое событие — кнопкой «Проверить».
Начать trial