Вебхуки
Вместо периодического опроса платформа сама вызывает ваш адрес при наступлении события. Это основной способ получать статусы доставки.
8.1 Подключение
Вебхук регистрирует администратор компании в веб-интерфейсе. Через API-ключ подписаться нельзя — это сделано намеренно, чтобы владелец ключа не мог перенаправить данные компании на посторонний адрес.
Требования к адресу:
- только HTTPS;
- только публичный адрес — внутренние и локальные адреса отклоняются;
- адрес проверяется не только при регистрации, но и при каждой отправке.
8.2 События
| Событие | Когда происходит |
|---|---|
order.status_changed | заказ сменил статус (из любого источника) |
route.dispatched | маршрут выдан водителю |
route.completed | маршрут завершён |
planning_job.finished | планирование завершилось (успешно или с ошибкой) |
vehicle_check.completed | завершён осмотр транспорта |
Пустой список событий означает, что не придёт ничего. Это противоположно логике разрешений у ключей, где пустой список даёт полный доступ. Перечисляйте события явно.
В отличие от разрешений ключа, названия событий проверяются при регистрации: опечатка вернёт ошибку со списком допустимых значений, а не создаст молчащую подписку.
8.3 Формат доставки
Платформа отправляет POST с заголовками:
| Заголовок | Содержимое |
|---|---|
X-DP-Event | название события |
X-DP-Delivery-Id | идентификатор доставки, неизменный при повторах |
X-DP-Timestamp | время отправки, Unix-секунды |
X-DP-Signature | sha256=<подпись> |
Примеры тел:
{"order_id":118234,"external_id":"РН-000123","old_status":"in_route","new_status":"confirmed"}
{"job_id":4471,"status":"done","route_ids":[9042,9043],
"summary":{"route_count":2,"unassigned_count":1},"error":null}
В событии
planning_job.finishedприходит только количество нераспределённых заказов. Причины запрашивайте отдельно черезGET /planning/jobs/{job_id}/.
8.4 Проверка подписи — обязательно
Без проверки подписи кто угодно сможет прислать вам ложный статус доставки.
Алгоритм:
- Взять заголовки
X-DP-TimestampиX-DP-Signature. - Убедиться, что метка времени отличается от текущей не более чем на 5 минут (защита от повторной отправки перехваченного запроса — платформа её не проверяет, это ваша ответственность).
- Составить строку:
<метка времени>+.+<тело запроса как есть>. - Вычислить HMAC-SHA256 этой строки с секретом вебхука.
- Сравнить с подписью из заголовка (без префикса
sha256=), обязательно используя сравнение, устойчивое к атаке по времени.
Ключевой момент: подписывается исходное тело запроса. Не разбирайте JSON и не собирайте его заново — порядок ключей и пробелы изменятся, и подпись не сойдётся. Берите байты ровно в том виде, в каком они пришли.
Пример на Python:
import hashlib, hmac, time
TOLERANCE = 300 # 5 минут
def verify(raw_body: bytes, headers, secret: str) -> bool:
ts = headers["X-DP-Timestamp"]
if abs(int(time.time()) - int(ts)) > TOLERANCE:
return False
signed = ts.encode() + b"." + raw_body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
presented = headers["X-DP-Signature"].removeprefix("sha256=")
return hmac.compare_digest(expected, presented)
8.5 Повторные попытки
- Успехом считается ответ с кодом 200–299. Любой другой код, включая перенаправления, считается неудачей.
- Перенаправления не выполняются — указывайте конечный адрес.
- Таймаут ответа — 10 секунд.
- Всего 5 попыток с интервалами 30 с, 60 с, 120 с, 240 с (около 7,5 минут).
- Неудачи не отключают вебхук автоматически.
Исключение из правила о пяти попытках. Если адрес не прошёл проверку безопасности, доставка помечается неудачной сразу, без единого повтора. Проверка выполняется перед каждой отправкой, и в неё входит разрешение доменного имени — поэтому кратковременный сбой DNS приводит к безвозвратной потере события. В журнале это выглядит как
blocked destinationбез кода ответа, одинаково для недоступного DNS, внутреннего адреса и неверной схемы. Следите за надёжностью DNS принимающего домена.
Журнал доставок доступен администратору компании в интерфейсе: видно статус каждой доставки, число попыток и код ответа. Оттуда же можно отправить событие повторно вручную — это штатный способ восстановиться после аварии на вашей стороне.
Что нужно учесть в приёмнике:
- Событие может прийти повторно. Отсекайте дубликаты по
X-DP-Delivery-Id— при повторах он не меняется (в отличие от подписи и метки времени). - Порядок событий не гарантирован. Статусы могут прийти не по порядку — опирайтесь
на поля
old_status/new_status, а не на очерёдность получения. - Отвечайте быстро, до истечения таймаута: примите запрос, поставьте в очередь, обработку выполняйте отдельно.
При ротации секрета переходного периода нет. Сначала научите приёмник проверять подпись двумя секретами сразу, и только потом меняйте секрет.