ProtoPays · API
кабинет

Webhook по платежу

При смене статуса внешнего платежа сервис ставит в очередь HTTP POST с телом application/json на callbackUri из создания платежа. Ниже — единственный стабильный публичный контракт (корень + data). Структура не зависит от канала оплаты (СБП, карта и т.д.).

Корень объекта

ПолеТипОбяз.Описание
typestringдаТип события (см. блок «Поле type»). Сейчас всегда payment.status.updated.
eventIdstringдаУникальный идентификатор одного доставленного события (например evt_ + ULID). Новое событие — новый eventId.
createdAtstringдаВремя формирования события, ISO 8601 с суффиксом Z (UTC).
dataobjectдаПубличные бизнес-поля платежа (см. следующий блок).

Поле type — тип события

type задаёт семантику webhook: по нему удобно выбирать обработчик (как topic в event-driven системе), а не разбирать тело наугад.

  • payment.status.updated — изменение статуса внешнего платежа; полезная нагрузка в data.

В будущем могут появиться другие значения type (например выплаты или споры). Неизвестные типы лучше логировать и пропускать без падения обработчика.

eventId и uuid — разные сущности

  • uuid — стабильный идентификатор платежа. Один и тот же uuid может фигурировать в нескольких webhook подряд (каждый раз при смене статуса).
  • eventId — уникальный идентификатор конкретного webhook-события. Используйте его для дедупликации доставки (повторная отправка того же события не должна обрабатываться дважды).

Для идемпотентности приёма уведомлений ориентируйтесь на eventId, а не на uuid в одиночку.

Жизненный цикл статусов

Типичная цепочка для обычной оплаты:

PENDING → COMPLETED / FAILED / CANCELLED

При апелляции возможны переходы через APPEAL и последующие события с тем же uuid.

  • События могут приходить не в хронологическом порядке относительно времени в вашей системе.
  • Возможны повторные доставки — используйте дедупликацию по eventId (см. общие правила).

data — обязательный контракт

Внутри data всегда только эти ключи (одинаковые для всех webhook):

ПолеТипОбяз.Описание
uuidstring (UUID)даПубличный идентификатор платежа (связка с вашей учётной системой).
orderIdstringдаВаш orderId из запроса создания.
statusstringдаТекущий статус в UPPERCASE (см. список ниже).
amountstringдаСумма в виде строки — так проще сохранить точность без ошибок JSON number. Лишние нули в дробной части могут быть сняты.
currencystringдаВалюта в UPPERCASE (например RUB).

meta (опционально)

Объект meta может отсутствовать. Если он есть, в нём могут быть вспомогательные поля (например reason, блок по апелляции).

Важно: поле meta не входит в стабильный публичный контракт и не гарантируется в будущих версиях в том же виде. Не стройте на нём критическую бизнес-логику (списание средств, закрытие заказа и т.д.) — опирайтесь на data и при необходимости уточняйте детали в поддержке.

Примеры JSON

Успешное завершение

{
  "type": "payment.status.updated",
  "eventId": "evt_01hz…",
  "createdAt": "2026-04-20T12:00:00Z",
  "data": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "orderId": "demo-001",
    "status": "COMPLETED",
    "amount": "1000",
    "currency": "RUB"
  }
}

Неуспех (пример)

Значение meta.reason иллюстративно; в проде может быть иной текст или код.

{
  "type": "payment.status.updated",
  "eventId": "evt_01hz…",
  "createdAt": "2026-04-20T12:05:00Z",
  "data": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "orderId": "demo-001",
    "status": "FAILED",
    "amount": "13420",
    "currency": "RUB"
  },
  "meta": {
    "reason": "insufficient_funds"
  }
}

Значения data.status

В webhook статус всегда в верхнем регистре:

  • PENDING — ожидает оплаты / обработки
  • COMPLETED — успешно завершён
  • FAILED — отказ / ошибка
  • CANCELLED — отменён
  • APPEAL — открыта апелляция

Терминальные (финальные) статусы для сценария оплаты без дальнейших переходов в ту же ветку: COMPLETED, FAILED, CANCELLED. PENDING и APPEAL — как правило промежуточные (по апелляции возможны последующие события с тем же uuid).

Рекомендации по обработке

Минимальный рабочий алгоритм:

  1. Проверить подпись запроса (если включена для вашего endpoint).
  2. По eventId убедиться, что это событие ещё не обрабатывали.
  3. Обновить локальное состояние платежа по data.uuid / data.orderId и data.status.
  4. Если статус терминальный — завершить пользовательский сценарий (выдача товара, закрытие заказа и т.д.).
  • Дедупликация доставки webhook: храните обработанные eventId (они не повторяются для разных событий).
  • Сопоставление с вашей системой: data.orderId и/или data.uuid.
  • Решение по итогу оплаты: опирайтесь на data.status; детали из meta — только справочно.
  • Повторы и порядок доставки — в общих правилах Webhooks.

Выплаты — отдельный контур: см. Webhook по выплатам.