Вебхуки

Когда задача заканчивается, на ваш адрес приходит POST по Standard Webhooks. Адрес — поле callback_url запроса; адрес по умолчанию для всех запросов можно задать в кабинете (раздел «Роутинг и вебхуки») или PATCH /v1/settings.

Адрес

https:// на публичный хост, без логина и пароля в адресе, до 2048 символов, порт — стандартный (без порта или :443). Частные адреса, localhost и внутренние имена (.local, .internal) не принимаются. Поле webhook.error задачи говорит, почему последняя попытка не засчитана: receiver answered <код>, receiver did not respond, адрес отвергнут или сбой на нашей стороне (доставка повторится).

Событие

Тело — {"type": "job.completed" | "job.failed", "timestamp", "data": <задача>} (схема WebhookEvent), подпись — в заголовках:

ЗаголовокЗначение
webhook-idid доставки — один у всех её повторов; по нему отбрасывайте дубли
webhook-timestampunix-секунды отправки; старые доставки отбрасывайте
webhook-signaturev1,<base64 HMAC-SHA256> от <webhook-id>.<webhook-timestamp>.<тело>

Ответ и повторы

Первая попытка уходит сразу, как задача закончилась. Ответьте 2xx за 10 секунд — до того, как начнёте обрабатывать. Иначе повтор через 30 секунд, 2 минуты, 10 минут и 1 час; после пятой неудачи доставка — failed (поле webhook задачи).

Проверка подписи

Секрет — GET /v1/webhooks/secret (whsec_…), один на аккаунт; POST /v1/webhooks/secret/rotate выпускает новый. Обе ручки — ключом управления с ролью разработчика или выше; секрет есть и в кабинете. Проверяйте готовой библиотекой Standard Webhooks по сырому телу запроса:

from standardwebhooks.webhooks import Webhook

payload = Webhook(secret).verify(raw_body, request.headers)  # исключение — подпись не сошлась