Webhooks
Получайте события доставки в реальном времени: delivered, bounced,complained, opened, clicked.
Настройка
В dashboard укажите URL, на который мы будем слать POST-запросы с событиями. При первой конфигурации автоматически генерируется секрет для HMAC-подписи — сохраните его, он показывается только один раз.
Формат события
{
"id": "ev_a1b2c3...",
"type": "email.delivered",
"createdAt": "2026-04-24T10:15:32Z",
"data": {
"emailId": "em_abc123...",
"to": "user@example.com",
"subject": "Order confirmation",
"tags": ["orders"]
}
}Типы событий
email.queued— письмо принято в очередьemail.sent— передано SMTP-серверу получателяemail.delivered— SMTP-сервер получателя подтвердил приёмemail.bounced— жёсткий отказ (ящик не существует)email.complained— получатель нажал «Это спам»email.opened— письмо открытоemail.clicked— клик по ссылке
Верификация HMAC
Каждый запрос подписывается заголовком X-Synapsea-Signature: sha256=.... Это HMAC от тела запроса с вашим секретом. Всегда проверяйте подпись — это защита от подделки событий.
Node.js (Express)
import crypto from "node:crypto";
import express from "express";
const app = express();
app.post("/webhooks/mail", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-synapsea-signature"];
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.SYNAPSEA_WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
if (signature !== expected) return res.status(401).send("invalid signature");
const event = JSON.parse(req.body.toString());
console.log(event.type, event.data.emailId);
res.json({ received: true });
});Python (Flask)
import hmac, hashlib, os, json
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/webhooks/mail")
def webhook():
signature = request.headers.get("X-Synapsea-Signature", "")
secret = os.environ["SYNAPSEA_WEBHOOK_SECRET"].encode()
expected = "sha256=" + hmac.new(secret, request.data, hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, expected):
abort(401)
event = request.json
print(event["type"], event["data"]["emailId"])
return {"received": True}Retry-политика
Если ваш endpoint вернул HTTP 2xx — событие считается доставленным. Если 4xx/5xx — мы делаем retry до 5 раз с exponential backoff: 1 мин, 5 мин, 15 мин, 1 час, 6 часов. После 5 неудачных попыток событие считается неуспешным.
Тестирование
Для локальной разработки используйте ngrokили webhook.site. История запросов доступна в dashboard → Webhooks.