Перейти к содержимому

Порядок и дедупликация

События доставляются хотя бы один раз: одно и то же событие может прийти дважды. Обрабатывайте каждый webhook-id один раз — сохраняйте обработанные id в той же транзакции, что и изменения от события.

События Порядок
Одного платежа По порядку: версия N отправляется только после того, как N−1 доставлена или не прошла.
Одной выплаты По порядку, так же.
Одного возврата Не гарантирован: processing возврата может прийти после его succeeded.
Разных объектов Порядка между ними нет.

Даже при упорядоченной доставке повтор, отправленный вручную, или гонка двух ваших серверов могут применить события не по порядку. Одно правило покрывает все случаи: храните версию и игнорируйте событие, версия которого не выше — payment_version, payout_version или refund_version.

// Inside one transaction: lock the row, compare, apply.
if (event.payment_version <= order.payment_version) return; // older or the same: nothing to do
order.status = event.status;
order.payment_version = event.payment_version;

Финальные статусы — succeeded, failed, cancelled — не меняются, поэтому старое событие не может их отменить.

Вебхук — это сигнал, источник истины — API. Если событие будто бы пропало или пришло не к месту, прочитайте объект — GET /v1/payments/{id}, GET /v1/payments/{id}/refunds, GET /v1/payouts/{id} — и сверьте с ним свою запись. Запускайте такую сверку и для заказов, которые остаются открытыми дольше ожидаемого.