Документация

Webhooks

Получайте события доставки в реальном времени: delivered, bounced,complained, opened, clicked.

Настройка

В dashboard укажите URL, на который мы будем слать POST-запросы с событиями. При первой конфигурации автоматически генерируется секрет для HMAC-подписи — сохраните его, он показывается только один раз.

Формат события

json
{
  "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)

webhook.js
javascript
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)

webhook.py
python
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.