Skip to content

Webhook Notifications ​

PSC sends webhook notifications to your server when payment events occur. Provide a callbackUrl (for payment webhooks) or notifyUrl (for refund webhooks) to receive real-time status updates without polling.


1. Payment Webhook ​

When a Hosted Payment order status changes, PSC sends a POST request to the callbackUrl you provided when creating the order.

Triggered Statuses ​

  • PROCESSING — Payment transaction detected on the blockchain
  • SUCCEEDED — Payment confirmed and completed

Request Headers ​

HeaderTypeDescriptionExample
X-TimestampLongNotification timestamp (milliseconds)1737554400000
X-SignatureStringRequest signature (Base64-encoded). Algorithm: Base64(HMAC-SHA256(timestamp + "\n" + "POST" + "\n" + path + "\n" + Base64(SHA256(requestBody)), apiSecret))base64-hmac-sha256

Request Body Fields ​

FieldTypeDescription
acquiringOrderIdStringPlatform order ID
paymentOrderIdStringPayment order ID
merchantOrderIdStringYour merchant order ID
statusStringOrder status: PROCESSING or SUCCEEDED
orderAmountObjectOriginal order amount
cryptoPaymentAmountObjectExpected crypto payment amount
cryptoPaidAmountObjectActual crypto amount paid by customer
cryptoPaymentDetailObjectBlockchain transaction details
createdTimeStringOrder creation time (UTC, ISO 8601)
paidTimeStringPayment completion time (UTC, ISO 8601)

Signature Verification ​

  1. Extract X-Timestamp and X-Signature from the request headers
  2. Read the complete raw request body as a string (do not re-serialize)
  3. Compute:
    • bodySha256Base64 = Base64(SHA256(requestBody))
    • signContent = timestamp + "\n" + "POST" + "\n" + path + "\n" + bodySha256Base64
    • expectedSignature = Base64(HMAC-SHA256(signContent, apiSecret))
  4. Compare expectedSignature with X-Signature
  5. Verify the timestamp is within 5 minutes to prevent replay attacks

Response Requirements ​

Return HTTP 200 immediately upon receiving the notification. Process any business logic asynchronously after returning 200 to avoid timeouts.

Any response other than HTTP 200, or a timeout, will trigger a retry.

Retry Schedule ​

AttemptDelay after previous failure
11 minute
25 minutes
315 minutes
430 minutes
51 hour
62 hours

After all retries are exhausted, query the order status manually using the Query Order API.

Examples ​

PROCESSING event:

json
{
  "acquiringOrderId": "ACQ20250121001",
  "paymentOrderId": "PAY20250121001",
  "merchantOrderId": "order-123456",
  "status": "PROCESSING",
  "orderAmount": {
    "value": "99.99",
    "currency": "USD"
  },
  "cryptoPaymentAmount": {
    "value": "100.000000",
    "currency": "USDT"
  },
  "cryptoPaidAmount": {
    "value": "100.000000",
    "currency": "USDT"
  },
  "cryptoPaymentDetail": {
    "chain": "TRON",
    "txHash": "0xabc123...",
    "fromAddress": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb",
    "toAddress": "TJRabPrwbZy45CUjUKdZLJ3WFzEKKE5Rmh",
    "blockNumber": 12345678,
    "confirmations": 3
  },
  "createdTime": "2025-01-21T10:30:00Z",
  "paidTime": null
}

SUCCEEDED event:

json
{
  "acquiringOrderId": "ACQ20250121001",
  "paymentOrderId": "PAY20250121001",
  "merchantOrderId": "order-123456",
  "status": "SUCCEEDED",
  "orderAmount": {
    "value": "99.99",
    "currency": "USD"
  },
  "cryptoPaymentAmount": {
    "value": "100.000000",
    "currency": "USDT"
  },
  "cryptoPaidAmount": {
    "value": "100.123456",
    "currency": "USDT"
  },
  "cryptoPaymentDetail": {
    "chain": "TRON",
    "txHash": "0xabc123...",
    "fromAddress": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb",
    "toAddress": "TJRabPrwbZy45CUjUKdZLJ3WFzEKKE5Rmh",
    "blockNumber": 12345678,
    "confirmations": 20
  },
  "createdTime": "2025-01-21T10:30:00Z",
  "paidTime": "2025-01-21T10:30:15Z"
}

2. Refund Webhook ​

When a refund status changes, PSC sends a POST request to the notifyUrl provided when creating the refund (or the merchant's default notify URL).

Request Headers ​

HeaderTypeDescriptionExample
X-TimestampLongNotification timestamp (milliseconds)1706428835000
X-SignatureStringRequest signature (Base64-encoded). Algorithm: Base64(HMAC-SHA256(timestamp + "\n" + "POST" + "\n" + path + "\n" + Base64(SHA256(requestBody)), apiSecret))base64-hmac-sha256

Request Body Fields ​

FieldTypeDescriptionExample
refundOrderIdStringPSC refund order IDREF_20260128120001
merchantRefundOrderIdStringMerchant refund order IDREFUND_20260128_001
acquiringOrderIdStringOriginal payment order IDORDER_20260128_001
statusStringRefund status: SUCCEEDED / FAILED / CLOSEDSUCCEEDED
refundCryptoAmountObjectRefund crypto amount{"value": "100.50", "currency": "USDT"}
refundCryptoAmount.valueStringRefund amount100.50
refundCryptoAmount.currencyStringRefund currencyUSDT
refundTimeString (ISO 8601)Time the refund was completed2026-01-28T12:05:30
refundCryptoTxHashStringOn-chain transaction hash of the refund0xabc123...
refundNetworkStringBlockchain network used for the refundTRON
refundChannelStringRefund channelEXCHANGE
exchangeOrderIdStringExchange-side order IDBINANCE_ORDER_123
merchantDeductAmountObjectAmount deducted from merchant{"value": "99.50", "currency": "USDT"}
merchantDeductAmount.valueStringDeducted amount99.50
merchantDeductAmount.currencyStringDeducted currencyUSDT
exchangeTypeStringExchange typeBINANCE_PAY

Signature Verification ​

  1. Extract X-Timestamp and X-Signature from the request headers
  2. Read the complete raw request body as a string (do not re-serialize)
  3. Compute:
    • bodySha256Base64 = Base64(SHA256(requestBody))
    • signContent = timestamp + "\n" + "POST" + "\n" + path + "\n" + bodySha256Base64
    • expectedSignature = Base64(HMAC-SHA256(signContent, apiSecret))
  4. Compare expectedSignature with X-Signature
  5. Verify the timestamp is within 5 minutes to prevent replay attacks

Response Requirements ​

Return HTTP 200 immediately upon receiving the notification. The response body is not strictly required — the following is recommended but not mandatory:

json
{
  "code": "00000",
  "message": "Success"
}

Any response other than HTTP 200 will be treated as a failure. Process any business logic asynchronously after returning 200 to avoid timeouts.

Examples ​

SUCCEEDED event:

json
{
  "refundOrderId": "REF_20260128120001",
  "merchantRefundOrderId": "REFUND_20260128_001",
  "acquiringOrderId": "ORDER_20260128_001",
  "status": "SUCCEEDED",
  "refundCryptoAmount": {
    "value": "100.50",
    "currency": "USDT"
  },
  "refundTime": "2026-01-28T12:05:30",
  "refundCryptoTxHash": "0xabc123...",
  "refundNetwork": "TRON",
  "refundChannel": "EXCHANGE",
  "exchangeOrderId": "BINANCE_ORDER_123",
  "merchantDeductAmount": {
    "value": "99.50",
    "currency": "USDT"
  },
  "exchangeType": "BINANCE_PAY"
}

FAILED event:

json
{
  "refundOrderId": "REF_20260128120002",
  "merchantRefundOrderId": "REFUND_20260128_002",
  "acquiringOrderId": "ORDER_20260128_002",
  "status": "FAILED",
  "refundCryptoAmount": {
    "value": "75.00",
    "currency": "USDT"
  },
  "refundNetwork": "TRON",
  "refundChannel": "EXCHANGE",
  "exchangeOrderId": "BINANCE_ORDER_456",
  "merchantDeductAmount": {
    "value": "74.25",
    "currency": "USDT"
  },
  "exchangeType": "BINANCE_PAY"
}

CLOSED event:

json
{
  "refundOrderId": "REF_20260128120003",
  "merchantRefundOrderId": "REFUND_20260128_003",
  "acquiringOrderId": "ORDER_20260128_003",
  "status": "CLOSED",
  "refundCryptoAmount": {
    "value": "50.00",
    "currency": "USDT"
  },
  "refundNetwork": "TRON",
  "refundChannel": "EXCHANGE",
  "exchangeOrderId": "BINANCE_ORDER_789",
  "merchantDeductAmount": {
    "value": "49.50",
    "currency": "USDT"
  },
  "exchangeType": "BINANCE_PAY"
}

Released under the MIT License.