Webhook EasyPay: структура данных платежей T-Bank

Этот документ описывает webhook, который EasyPay отправляет на ваш сервер при успешной оплате через T-Bank (карта или СБП). Аналогичный документ для Stripe-платежей — Webhook EasyPay: структура данных платежей Stripe.

Общая информация

EasyPay получает уведомление об оплате от T-Bank, нормализует его и отправляет вам очищенный объект — без внутренних технических полей платёжной системы. В отличие от Stripe, где событий несколько (подписки, возвраты, диспуты), для T-Bank сейчас передаётся одно событие — успешный платёж.

T-Bank работает с рублёвыми платежами. Сумма передаётся в копейках (минорных единицах): 1000 = 10.00 ₽.

Как передаётся webhook

Мы отправляем данные на ваш webhook endpoint:

Параметр

Значение

Метод

POST

Content-Type

application/json

Timeout

10 секунд на ответ

Успешный ответ

любой 2xx

Повторы

до 6 попыток с нарастающим интервалом: ~1 → 3 → 9 → 27 → 30 минут (всего ~70 минут)

Когда мы повторяем отправку

Повторяем, если повтор способен помочь:

  • ответ 5xx, обрыв соединения или отсутствие ответа за 10 секунд;

  • ответ 429 (слишком много запросов), а также 408, 409, 425.

На остальные 4xx (400, 401, 404 и подобные) повторов не будет — повтор их не исправит. Вместо этого срабатывает внутренний алерт, и с вами свяжется команда EasyPay.

Если вы отдаёте заголовок Retry-After (например, вместе с 429 или 503), мы его учитываем, но ждём не дольше 30 минут.

Идемпотентность на вашей стороне обязательна

Если ответ не пришёл за 10 секунд, мы не знаем, дошёл ли запрос, и повторим отправку. Доставка гарантируется по принципу «хотя бы один раз», поэтому один и тот же платёж может прийти к вам дважды.

Ключ идемпотентности — Payment.Data.ep_payment_uuid: он уникален для платежа и одинаков во всех повторах. Если такой платёж уже обработан, просто верните 2xx.

У платежей, созданных публичной ссылкой на оплату (pay.appload.tech/<slug>), ep_payment_uuid приходит null — там нет idempotency_key, его передаёт только тот, кто создаёт платёж через API. Для таких платежей ключом идемпотентности служит Payment.OrderId: он уникален для каждой попытки оплаты и не меняется между повторами.

Поддерживаемые события

Payload содержит поле Event, которое указывает тип события.

Event

Описание

TBank.payment.succeeded

Успешная оплата (разовый платёж картой или через СБП)

Структура payload

{
  "Event": "TBank.payment.succeeded",
  "Payment": {
    "Status": "CONFIRMED",
    "Success": true,
    "ErrorCode": "0",
    "Amount": 1000,
    "OrderId": "<string>",
    "Pan": "<masked>",
    "Data": {
      "Email": "<string>",
      "Phone": "<string|null>",
      "ep_pid": "<string>",
      "ep_product_id": "<string>",
      "ep_payment_uuid": "<string|null>",
      "ep_order": "<string|null>"
    }
  }
}

Описание полей

Поле

Тип

Описание

Event

string

Тип события. Всегда TBank.payment.succeeded.

Payment

object

Объект платежа.

Payment.Status

string

Статус платежа в T-Bank. Для успешной оплаты — CONFIRMED.

Payment.Success

boolean

Признак успешности — true.

Payment.ErrorCode

string

Код ошибки T-Bank. "0" — без ошибок.

Payment.Amount

number

Сумма в копейках (минорные единицы). 1000 = 10.00 ₽.

Payment.OrderId

string

Идентификатор заказа на стороне T-Bank (генерируется EasyPay).

Payment.Pan

string

Маскированный номер карты. Для оплаты через СБП — маскированный телефон.

Payment.Data

object

Дополнительные данные платежа.

Payment.Data.Email

string

Email клиента.

Payment.Data.Phone

string

null

Payment.Data.ep_pid

string

Ваш идентификатор партнёра в EasyPay.

Payment.Data.ep_product_id

string

Идентификатор оплаченного продукта.

Payment.Data.ep_payment_uuid

string | null

Уникальный идентификатор платежа. Совпадает с idempotency_key, который вы передали при создании платежа через API. null — если платёж пришёл по публичной ссылке на оплату (там idempotency_key передавать негде); тогда используйте Payment.OrderId.

Payment.Data.ep_order

string | null

Ваш идентификатор заказа — тот, что вы передали при создании платежа: в параметре ?d= публичной ссылки (order_id) или в поле external_order_id ручки create_partner_tbank_payment. Возвращается ровно в том виде, в котором вы его прислали. null — если идентификатор не передавали.

Пример payload

{
  "Event": "TBank.payment.succeeded",
  "Payment": {
    "Status": "CONFIRMED",
    "Success": true,
    "ErrorCode": "0",
    "Amount": 1000,
    "OrderId": "a1b2c3d4e5f64a7b8c9d0e1f",
    "Pan": "220070******0000",
    "Data": {
      "Email": "customer@example.com",
      "Phone": null,
      "ep_pid": "your_partner_name",
      "ep_product_id": "42",
      "ep_payment_uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "ep_order": "order-2026-0042"
    }
  }
}

FAQ

Как сопоставить платёж с моим заказом?

Передавайте свой идентификатор заказа при создании платежа — он вернётся в Payment.Data.ep_order ровно таким, каким вы его прислали:

  • публичная ссылка на оплату — поле order_id в параметре ?d= (см. «Checkout: Публичная T-Bank ссылка — параметры через Base64»);

  • create_partner_tbank_payment — поле external_order_id.

Если идентификатор не передавали, у платежей через API остаётся Payment.Data.ep_payment_uuid (= ваш idempotency_key), а у платежей по публичной ссылке — только Payment.OrderId (наш внутренний идентификатор попытки; он стабилен, но о вашем заказе ничего не знает).

Какой продукт оплачен?

Идентификатор продукта — в Payment.Data.ep_product_id.

Какая сумма и валюта?

Payment.Amount — сумма в копейках (например, 1000 = 10.00 ₽). T-Bank работает в рублях (RUB).

Чем платёж картой отличается от СБП?

Событие одно — TBank.payment.succeeded. Способ оплаты виден по полю Payment.Pan: для карты это маскированный номер карты, для СБП — маскированный телефон.