Payment Webhook
This is a webhook interface, implemented by the Game SVR with the callback URL configured in the SUD OP console. The SUD OP SVR calls this interface when a payment or refund status changes, notifying the Game SVR to handle the delivery or refund result.
Interface Description
Interface Name pay.notify
Description Payment webhook. The SUD OP SVR proactively calls the callback URL configured by the Game SVR, notifying the Game SVR to handle item delivery or refund results.
Note: This interface requires service communication secondary encryption and signatures: the callback request must be signature-verified and decrypted before any business logic runs. This effectively prevents data tampering and leakage.
Interface Information
| Item | Value |
|---|---|
| Caller | SUD OP SVR |
| Provider | Game SVR |
| Trigger timing | When a payment or refund status changes |
Call Method
HTTPS Call
POST <Game custom callback URL>The callback URL is configured by the Game in the SUD OP console. Please use an HTTPS address.
Request Parameters - Body
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| id | string | Yes | Webhook notification ID. Globally unique, remains unchanged when SUD OP retries; the Game SVR should use this field as the idempotency key | |
| create_time | number | Yes | Webhook notification creation time (second-level timestamp) | |
| event | string | Yes | Event type, enum value | |
| payload | object | Yes | Event data. Different event types correspond to different data structures, see the description below |
Item Delivery Notification: pay_goods_deliver_notify
payload field description:
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| env | number | Yes | Environment: 0-production, 1-sandbox | |
| out_trade_no | string | Yes | Business order number | |
| sud_trade_no | string | Yes | SUD order number | |
| product_id | string | Yes | Product ID | |
| product_name | string | Yes | Product name | |
| quantity | number | Yes | Purchase quantity | |
| unit_price | number | Yes | Unit price (in cents) | |
| attach | string | No | Pass-through data |
Request example:
{
"id": "xxx",
"create_time": 1745136000,
"event": "pay_goods_deliver_notify",
"payload": {
"env": 0,
"out_trade_no": "BIZ20250420001",
"sud_trade_no": "SUD20250420001",
"product_id": "product_001",
"product_name": "Coin Pack",
"quantity": 1,
"unit_price": 600,
"attach": ""
}
}Refund Notification: pay_refund_notify
payload field description:
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| env | number | Yes | Environment: 0-production, 1-sandbox | |
| sud_refund_no | string | Yes | SUD refund number | |
| out_trade_no | string | Yes | Business order number corresponding to the refund | |
| sud_trade_no | string | Yes | SUD order number corresponding to the refund | |
| refund_amount | number | Yes | Refund amount (in cents) | |
| reason | string | No | Refund reason |
Request example:
{
"id": "xxx",
"create_time": 1745136000,
"event": "pay_refund_notify",
"payload": {
"env": 0,
"out_trade_no": "BIZ20250420001",
"sud_trade_no": "SUD20250420001",
"sud_refund_no": "REF20250420001",
"refund_amount": 600,
"reason": "deliver pay products failed"
}
}Response
The returned JSON data package
| Field | Type | Description |
|---|---|---|
| errcode | int32 | Error code. 0 indicates the Game SVR has successfully processed this notification (including a duplicate request that passed idempotency judgment), and SUD OP will not retry; a non-0 value indicates processing failure, and SUD OP will retry according to the "Timeout and Retry" policy below |
| errmsg | string | Error message |
Response Example
{
"errcode": 0,
"errmsg": "ok"
}Timeout and Retry
| Item | Requirement |
|---|---|
| Game response timeout threshold | ≤ 5 s |
| Conditions that trigger a retry | The Game SVR does not respond within the timeout threshold, returns a non-200 HTTP status code, or returns a non-zero errcode |
| Total retry count | Up to 15 times |
| Retry interval (seconds) | 15, 15, 30, 180, 600, 1200, 1800, 1800, 1800, 3600, 10800, 10800, 10800, 21600, 21600 (approximately 24 hours in total) |
Retry requests keep the same top-level
idas the first request. The Game SVR must useidfor idempotency judgment; when an idempotency hit occurs, simply returnerrcode: 0and do not deliver or refund again.
Authentication
When SUD OP calls this interface, it always carries encryption and signature information in the request; there is no plaintext webhook mode. The Game SVR must verify the signature and decrypt the request to confirm the request source is legitimate. If verification fails, reject the request directly (return a non-200 HTTP status code); do not enter the business response flow.
Notes
- The Game SVR must verify the signature. If verification fails, reject the request directly (return a non-200 HTTP status code) to avoid forged requests triggering delivery or refund processing.
- Idempotency key: use the top-level
idas the unique idempotency key. Theidremains unchanged when SUD OP retries; the "delivery notification" and "refund notification" for the same order use differentids, so they are naturally distinguished. - At the business layer, it is recommended to also perform order status validation based on
out_trade_no/sud_trade_no/sud_refund_noto prevent out-of-order arrival (such as a refund callback arriving before the delivery callback). - Requests whose
create_timediffers from the server's current time by more than 5 minutes should be rejected directly to prevent replay attacks.
