Получение уведомлений
При наступлении события Pert отправляет HTTP POST на URL вашего webhook. Тело запроса одинаково для всех
подписчиков одного и того же события — рабочее пространство передаётся отдельным заголовком, что позволяет
переиспользовать одну подпись для всей рассылки.
HTTP-заголовки
| Заголовок | Описание |
|---|---|
Content-Type |
Всегда application/json |
X-Webhook-Id |
UUID вашего webhook |
X-Webhook-Event-Id |
UUID события — используйте как ключ идемпотентности |
X-Webhook-Timestamp |
Unix-время отправки в миллисекундах |
X-Webhook-Workspace-Id |
UUID рабочего пространства, в котором произошло событие |
X-Webhook-Signature |
Подпись тела запроса (base64). См. Верификация подписи |
Workspace в заголовке, а не в теле
Тело запроса идентично для всех подписчиков одного события. Это позволяет вычислить подпись один раз и
использовать её при доставке всем webhook — снижает нагрузку на KMS и ускоряет fan-out. Если вам нужно
различать события по рабочим пространствам, читайте X-Webhook-Workspace-Id.
Тело запроса
{
"event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event_type": "transaction.created",
"category": "Transactions",
"timestamp": "2026-04-23T10:15:30Z",
"data": {
"...": "данные события"
}
}
| Поле | Тип | Описание |
|---|---|---|
event_id |
UUID | Уникальный идентификатор события. Совпадает с заголовком X-Webhook-Event-Id |
event_type |
string | Тип события (например, transaction.created) |
category |
string | Категория, по которой ваш webhook подписан |
timestamp |
string | ISO 8601, время наступления события |
data |
object | Полезная нагрузка события — структура зависит от event_type |
Структура data описана для каждого event_type отдельно — см. Типы событий.
Ответ вашего сервера
Ваш сервер должен вернуть HTTP-код 2xx (например, 200 OK) в течение 10 секунд.
| Условие | Что произойдёт |
|---|---|
| Код 2xx за ≤ 10 секунд | Доставка считается успешной, статус записи в истории — success |
| Код не 2xx | Доставка считается ошибкой, запланирован retry (см. Повторные попытки) |
| Таймаут (> 10 секунд) | Соединение разрывается, доставка считается ошибкой, запланирован retry |
| Ошибка TCP / DNS / TLS | Доставка считается ошибкой, запланирован retry |
Тело ответа не используется логикой доставки. Pert сохраняет первые 4 КБ тела ответа в истории доставок — чтобы вам было проще диагностировать проблемы.
Не блокируйте ответ обработкой
Не выполняйте долгую обработку синхронно. Сохраните payload в очередь или БД и сразу возвращайте 200 OK —
затем обрабатывайте событие в фоне. Это исключает таймауты и ненужные retry, когда ваш сервер на самом деле
получил событие.
Пример обработчика
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/webhook")
def webhook():
# 1. Сначала проверьте подпись над сырым телом
body = request.get_data()
signature = request.headers.get("X-Webhook-Signature", "")
if not verify_webhook(body, signature, PUBLIC_KEY_B64):
abort(401)
# 2. Только теперь парсите JSON и кладите в очередь
event = request.get_json()
queue.publish(event)
# 3. Возвращайте 200 как можно быстрее
return "", 200
import express from "express";
const app = express();
// ВАЖНО: raw-тело нужно для верификации подписи
app.use("/webhook", express.raw({ type: "application/json" }));
app.post("/webhook", (req, res) => {
const signature = req.headers["x-webhook-signature"];
if (!verifyWebhook(req.body, signature, PUBLIC_KEY_B64)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
queue.publish(event);
res.sendStatus(200);
});
func webhookHandler(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20))
if err != nil {
http.Error(w, "read", http.StatusBadRequest)
return
}
sig := r.Header.Get("X-Webhook-Signature")
if !verifyWebhook(body, sig, publicKeyB64) {
http.Error(w, "invalid signature", http.StatusUnauthorized)
return
}
var event WebhookPayload
if err := json.Unmarshal(body, &event); err != nil {
http.Error(w, "json", http.StatusBadRequest)
return
}
queue.Publish(event)
w.WriteHeader(http.StatusOK)
}
См. полные примеры верификации подписи на странице Верификация подписи.