Webhooks

Мгновенные уведомления о платежах с подписью HMAC-SHA256

Как работают webhooks

Когда статус платежа меняется, Pay Bot отправляет POST-запрос на ваш URL с данными о событии.

Регистрация

bash
Скачать
curl -X POST https://payapi.aibot.kz/me/webhooks \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yoursite.com/webhook",
    "events": ["payment.completed", "payment.cancelled", "payment.expired"]
  }'

Секрет для подписи генерируется автоматически и показывается один раз.

Типы событий

  • payment.completed — платёж успешно завершён
  • payment.cancelled — платёж отменён клиентом
  • payment.expired — QR-код или инвойс истёк (30 минут)

Формат payload

json
Скачать
{
  "id": "wh_evt_abc123def456",
  "event": "payment.completed",
  "created_at": "2026-04-02T12:30:00Z",
  "data": {
    "operation_id": 14836487620,
    "amount": 5000,
    "status": "Paid"
  }
}

Подпись HMAC-SHA256

Каждый webhook подписан. Заголовки:

  • X-Webhook-ID — уникальный ID события
  • X-Webhook-Timestamp — Unix timestamp
  • X-Webhook-Signaturesha256=HMAC(secret, timestamp.body)

Верификация (Python)

python
Скачать
import hmac, hashlib, time

def verify_webhook(secret, timestamp, body, signature):
    expected = hmac.new(
        secret.encode(), f"{timestamp}.{body}".encode(), hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(f"sha256={expected}", signature):
        raise ValueError("Invalid signature")
    if abs(time.time() - int(timestamp)) > 300:
        raise ValueError("Replay attack")

Верификация (JavaScript)

javascript
Скачать
const crypto = require("crypto");

function verifyWebhook(secret, timestamp, body, signature) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${body}`)
    .digest("hex");
  if (`sha256=${expected}` !== signature) throw new Error("Invalid signature");
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) throw new Error("Replay");
}

Retry Policy

ПопыткаЗадержка
1Мгновенно
230 секунд
35 минут
430 минут
52 часа

После 5 неудачных попыток webhook помечается как failing и доставка прекращается.