IskraGen

Webhooks

Получайте уведомления о завершении задач без polling'а

Webhooks — это HTTP POST-запросы, которые IskraGen отправляет на ваш URL, когда задача завершается (успехом или неудачей). Полезно для длинных генераций — видео, музыка, аудио — чтобы не опрашивать GET /v1/generations/:id в цикле.

Зачем использовать

Три основных use case'а:

  • Уведомление пользователя о завершении. Запустили рендер видео на 30 секунд → ушли по своим делам → webhook прилетел → отправили push / email / in-app сообщение «готово».
  • Запись результата в свою БД. При generation.succeeded получаете финальный URL медиа из payload, сохраняете в свою таблицу или копируете на свой S3 для долговременного хранения.
  • Триггер пайплайна пост-обработки. Сразу после генерации запускаете апскейл, лицензирование, водяной знак, монтаж в общий ролик — без задержки на polling.

Как создать webhook

Управление endpoint'ами происходит через API. UI в личном кабинете пока в разработке.

1. Создать endpoint

curl https://api.iskragen.ru/v1/webhook-endpoints \
  -H "Authorization: Bearer $ISKRAGEN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/iskragen",
    "eventTypes": ["generation.succeeded", "generation.failed"]
  }'

Ответ 201:

{
  "id": "01HQ...uuid",
  "url": "https://your-app.com/webhooks/iskragen",
  "secret": "whsec_BASE64SECRET...",
  "eventTypes": ["generation.succeeded", "generation.failed"]
}

Сохраните secret сразу — он показывается только один раз. Им вы будете проверять подпись входящих запросов.

2. Список endpoint'ов

curl https://api.iskragen.ru/v1/webhook-endpoints \
  -H "Authorization: Bearer $ISKRAGEN_KEY"

3. Ротация секрета

curl -X POST https://api.iskragen.ru/v1/webhook-endpoints/<id>/rotate-secret \
  -H "Authorization: Bearer $ISKRAGEN_KEY"

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

4. Удаление

curl -X DELETE https://api.iskragen.ru/v1/webhook-endpoints/<id> \
  -H "Authorization: Bearer $ISKRAGEN_KEY"

События

  • generation.succeeded — задача завершилась успешно. В payload — финальный URL результата.
  • generation.failed — задача провалилась окончательно (после всех retry). Списанные средства возвращены на баланс автоматически.

Подпись

Каждый запрос подписан по схеме Standard Webhooks. Заголовки:

ЗаголовокЧто внутри
webhook-idУникальный ID сообщения (UUID), для идемпотентности на вашей стороне.
webhook-timestampUnix-время (секунды), когда подпись посчитана.
webhook-signaturev1,<base64-hmac-sha256> — HMAC от ${msgId}.${timestamp}.${body} с вашим секретом.

Проверьте, что webhook-timestamp отличается от текущего не более чем на 5 минут — иначе считайте подпись невалидной (защита от replay-атак).

Пример обработчика (Node.js + Express)

import crypto from 'node:crypto';
import express from 'express';

const SECRET = process.env.ISKRAGEN_WEBHOOK_SECRET; // "whsec_..."

const app = express();
// raw body нужен для побайтовой подписи — НЕ используйте express.json() до проверки
app.post('/webhooks/iskragen', express.raw({ type: 'application/json' }), (req, res) => {
  const msgId = req.header('webhook-id');
  const timestamp = req.header('webhook-timestamp');
  const signatureHeader = req.header('webhook-signature');
  const body = req.body.toString('utf8');

  if (!msgId || !timestamp || !signatureHeader) return res.status(400).end();
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.status(400).end();

  const key = Buffer.from(SECRET.replace(/^whsec_/, ''), 'base64');
  const expected = crypto.createHmac('sha256', key)
    .update(`${msgId}.${timestamp}.${body}`)
    .digest('base64');

  const valid = signatureHeader.split(' ').some((sig) => {
    const [scheme, sigB64] = sig.split(',');
    return scheme === 'v1' && crypto.timingSafeEqual(
      Buffer.from(sigB64), Buffer.from(expected),
    );
  });

  if (!valid) return res.status(401).end();

  const event = JSON.parse(body);
  // event.type === "generation.succeeded" | "generation.failed"
  // event.data.generation — финальный объект генерации с URL результата

  // Ответьте 2xx как можно быстрее, тяжёлую работу делайте в фоне
  res.status(204).end();
});

app.listen(3000);

Ретраи

При ошибке (HTTP ≥ 400, кроме 410, или таймаут 10 секунд) IskraGen ретраит до 15 раз с экспоненциальным бэк-оффом — от 5 секунд до 3 суток. Если ваш endpoint вернёт HTTP 410 Gone, он будет автоматически отключён. После 30 × 24 подряд неудач endpoint также деактивируется.

Идемпотентность

При ретраях один и тот же webhook-id будет повторяться. Сохраняйте обработанные msgId (например, в Redis с TTL 24 часа) и сразу отвечайте 2xx без обработки на дубликат — иначе рискуете дважды сохранить результат или дважды дёрнуть пост-обработку.

См. также Interactive API Reference → раздел Webhook Endpoints.