На странице
Payload
Разбирайте версионированный webhook-envelope и полный снимок инвойса или выплаты в поле data.
Тело каждого вебхука — версионированный envelope. Объект data совпадает с контрактом ресурса для мерчанта из соответствующего status API, поэтому обработчик применяет полный снимок, а не собирает состояние из частичных изменений.
Envelope
| Поле | Тип | Контракт |
|---|---|---|
event_id |
string | Стабильный ID с префиксом evt_…, совпадает с X-Webhook-Id и не меняется между retry и replay |
event_type |
string | Одно из значений каталога событий |
version |
integer | Версия схемы payload. Текущая версия — 1 |
occurred_at |
Unix seconds | Время перехода ресурса; в отличие от времени доставки не меняется при retry |
data |
object | Полный снимок инвойса или выплаты для этого события |
Сохраните event_id, event_type, version и raw body до запуска тяжёлой обработки. Если версия схемы не поддерживается вашей интеграцией, отклоните её явно — не пытайтесь угадать структуру.
Payload инвойса
Пример: invoice.paid.
{
"event_id": "evt_J7EEYeL9pZJukfj2c5OQ44",
"event_type": "invoice.paid",
"version": 1,
"occurred_at": 1739281200,
"data": {
"invoice_id": "inv_5CcyDYmMUGtzYL10q0Iimr",
"project_id": "prj_xFukZuAJZR06pLVBh3uwzv",
"status": "paid",
"is_final": true,
"is_test": false,
"payment_url": "https://checkout.paymos.io/invoice/inv_5CcyDYmMUGtzYL10q0Iimr",
"order": {
"external_id": "order-12345",
"client_id": "customer-67890",
"amount": "100.00",
"currency": "USD"
},
"payment": {
"currency": "USDT",
"network": "TRC20",
"chain_id": 728126428,
"contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"expected": "50.00",
"address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
"exchange_rate": "2.00",
"paid": "50.00",
"remaining": "0",
"fee": "0.50",
"net": "49.50",
"transfers": [
{
"tx_hash": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
"amount": "50.00",
"status": "confirmed",
"created_at": 1739281020,
"confirmed_at": 1739281200,
"required_confirmations": 19,
"estimated_confirmation_at": 1739281080,
"explorer_url": "https://tronscan.org/#/transaction/abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
]
},
"expires_at": 1739284200,
"completed_at": 1739281200,
"created_at": 1739277600,
"updated_at": 1739281200
}
}
Поле data инвойса повторяет ответ Получения инвойса. Поля, которых ещё нет в текущем состоянии, равны null или не сериализуются; источником состояния остаются status и is_final.
Payload выплаты
Пример: withdrawal.completed.
{
"event_id": "evt_CbYeOgBp9Kt2U3j74fxxLl",
"event_type": "withdrawal.completed",
"version": 1,
"occurred_at": 1739281200,
"data": {
"withdrawal_id": "wdr_7K2M9P4Q8R1X5Z3A0bC2dE",
"external_order_id": "payout-12345",
"status": "completed",
"is_final": true,
"is_test": false,
"amount": "25.00",
"fee": "0.50",
"currency": "USDT",
"network": "TRC20",
"destination_address": "TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9",
"tx_hash": "7f8a9b0c1d2e3f4a5b6c7d8e9f00112233445566778899aabbccddeeff001122",
"explorer_url": "https://tronscan.org/#/transaction/7f8a9b0c1d2e3f4a5b6c7d8e9f00112233445566778899aabbccddeeff001122",
"created_at": 1739277600,
"completed_at": 1739281200
}
}
Поле data выплаты повторяет ответ Получения выплаты. tx_hash и explorer_url заполняются, когда доступна отслеживаемая on-chain транзакция; они не заменяют поле status.
Совместимость
- Новые дополнительные поля могут появляться без смены версии. Игнорируйте поля, которые обработчик не использует.
- Смысл существующих полей не меняется внутри одной версии payload.
- Идентификаторы и decimal-суммы обрабатывайте как строки. Не разбирайте prefixed ID как UUID, а деньги — как binary floating point.
- Сначала проверяйте подпись по raw bytes и только потом разбирайте JSON. Повторная сериализация меняет подписанные данные.