Webhooks
Если при создании задачи передать webhook_url, после завершения задачи (статус done или failed) мы отправим на этот адрес POST-запрос с объектом задачи в теле — тем же, что возвращает GET /media/tasks/:id.
Тело запроса
Тело — JSON-объект задачи (см. Получение задачи). Пример:
{ "code": 0, "id": "6a61e021a6e77553a989c41d", "model": "kling-v3", "status": "done", "result": [ { "url": "https://.../6a61e021a6e77553a989c41d_result.mp4" } ], "created_at": 1784799265}Заголовки
| Заголовок | Значение |
|---|---|
X-Gptunnel-Event | Тип события: task.done или task.failed |
X-Gptunnel-Delivery | Идентификатор задачи |
X-Gptunnel-Signature | Подпись тела: t=<unix>,v1=<hex> |
Проверка подписи
Подпись позволяет убедиться, что запрос пришёл от нас. Формат заголовка совместим со схемой Stripe:
X-Gptunnel-Signature: t=1784799265,v1=5f8c...e21aГде t — момент подписи (Unix, секунды), v1 — HMAC-SHA256 в hex от строки "<t>.<тело запроса>". Секрет подписи — ваш API-ключ.
Чтобы проверить подпись: возьмите значение t и сырое тело запроса, вычислите HMAC-SHA256 от строки `${t}.${rawBody}` с вашим API-ключом в качестве секрета и сравните с v1. Рекомендуется также отклонять запросы со слишком старым t.
import { createHmac, timingSafeEqual } from 'crypto'
function verify(rawBody: string, header: string, apiKey: string): boolean { const parts = Object.fromEntries( header.split(',').map((kv) => kv.split('=')), ) const expected = createHmac('sha256', apiKey) .update(`${parts.t}.${rawBody}`) .digest('hex') const a = Buffer.from(expected) const b = Buffer.from(parts.v1 ?? '') return a.length === b.length && timingSafeEqual(a, b)}import hashlibimport hmac
def verify(raw_body: str, header: str, api_key: str) -> bool: parts = dict(kv.split('=', 1) for kv in header.split(',')) expected = hmac.new( api_key.encode(), f"{parts['t']}.{raw_body}".encode(), hashlib.sha256, ).hexdigest() return hmac.compare_digest(expected, parts.get('v1', ''))Повторные попытки
Ваш эндпоинт должен ответить статусом 2xx. Если доставка не удалась, мы повторим её несколько раз с нарастающими паузами (примерно через 5 с, 20 с, 60 с и 180 с).