# Callback Transaction Result
# Callback Interface Signature Verification
Purpose of Signature Verification
During API requests, there is a risk of data being tampered with by a middleman while being transmitted over the public network. To ensure the integrity and trustworthiness of the callback data, the platform supports and strongly recommends that merchants perform signature verification when receiving the callback.
Setup Method
Log in to the [Cashier Backend] → [Developer Center] → [Callback Address] → Add/Edit.
Signature Verification Steps
The signature verification logic is generally the same as the API request signature, with the key difference being that the data source is the received callback content.
1.Obtain the Signature
Retrieve the signature field from the HTTP request Header:
sign: {Platform-generated signature string}
2.Obtain the Callback Parameters
Store the JSON parameters from the callback Body in a Map (dictionary) structure in key-value form.
3.Add Public Parameters
Also retrieve the following fields from the Header and include them in the Map for signature verification:
access_key
timestamp
nonce
4.Construct the String to Be Signed
Sort all the keys in the Map in ASCII order from smallest to largest, and concatenate them into the following format:
key1=value1&key2=value2&...&keyN=valueN
5.Perform Signature Calculation
- Use the
secret_key
bound to the merchant's backend to process the above string as follows:- Encrypt using the
HMAC_SHA1
algorithm - Base64 encode the result to obtain the local
sign
value
- Encrypt using the
6.Compare Signatures
Compare the locally generated sign
with the sign
provided in the Header by the platform:
- ✅ If they match → Signature verification passes, and business logic can be processed
- ❌ If they don't match → Reject processing and consider logging the event for troubleshooting
# Payment Callback
Callback Data Example
{
"currencyType": "USD",
"orderActualAmount": "1",
"orderId": "OCRYPPAID202307310902391690794159441DOCKER020000000400001108",
"tradeHash": "0x806d5b3da29c8426a644e2ded85b865b37504dcdec4cfb9db13af5e962815528",
"orderFee": "1",
"orderStatus": "Completed",
"chainType": "ETH",
"externalOrderId": "402297358314559082",
"addressTo": "0xe072c63c1e04f8c6f36133f6629f66778147d5d8",
"orderAmount": "1",
"orderTime": 1690794159000,
"exchangeRate": "0.983",
"orderStatusCode": 4,
"orderPayTime": 1690794247000,
"addressFrom": "0x0cbfd17ae9e1d6d881b2cade71277f48abf64d24",
"tokenType": "USDT"
}
Callback Field Description
Parameter Name | Type | Description |
---|---|---|
currencyType | String | Fiat currency type (e.g., USD) |
orderActualAmount | String | Actual payment amount |
orderId | String | Platform order ID |
tradeHash | String | Blockchain transaction hash |
orderFee | String | Transaction fee amount |
orderStatus | String | Order status text (e.g., Completed) |
orderStatusCode | int64 | Order status code (see explanation below) |
chainType | String | Blockchain main chain type (e.g., ETH) |
externalOrderId | String | Merchant order ID |
addressTo | String | Receiving address |
addressFrom | String | Sending address |
orderAmount | String | Original order amount |
orderTime | int64 | Order creation time (Unix timestamp in ms) |
orderPayTime | int64 | Actual payment time (Unix timestamp in ms) |
exchangeRate | String | Exchange rate |
tokenType | String | Cryptocurrency type (e.g., USDT) |
markStatus | String | Mark status (if applicable) |
errorMsg | String | Error message (in Chinese) |
errorMsgEn | String | Error message (in English) |
Order Status Code Description (orderStatusCode)
Status Code | Description |
---|---|
1 | Pending Payment: Order created successfully, awaiting user payment |
2 | On-chain Confirmation: User clicked "I have paid," awaiting blockchain confirmation |
4 | Completed: Payment successful, the platform will automatically send the callback notification |
8 | Payment Amount Mismatch: Callback notification sent again, please credit based on actual amount |
16 | Timeout: User did not pay on time, no further callbacks |
32 | Unpaid: Address expired and will not be processed |
⚠️ Callback Handling Recommendations
- Once the callback is successfully verified and
orderStatusCode == 4
, the payment is considered successful. The business process (e.g., crediting account) should be performed immediately. - The platform may resend callbacks due to network issues. Please ensure idempotent processing to avoid duplicate crediting.
- If verification fails or data is abnormal, please log the issue and return an error response. The platform will automatically retry up to 2 times within 30 minutes.
Manual Callback Explanation
Merchants can manually trigger a callback in the backend order management system to fix missed callbacks. However, please note the following:
- If the order status is not in a final state (e.g., Pending Payment, Confirming), manual callbacks are not recommended.
- If a manual callback is triggered but the order is not yet completed, the platform will still send the callback again when the status changes to a final state. Merchants should ensure deduplication at the business layer.
# Transfer Callback
Callback Data Example
{
"orderAmount": "1",
"orderTime": 1690794160000,
"orderId": "OCRYPDRAW202307310902401690794160841DOCKER020000000200001109",
"orderStatusCode": 2,
"tradeHash": "0xe9d043c9cbdb96ed7a71c5a0923baabe9e23316b3f1b0a01975bcd6d69b41fa3",
"orderFee": "0.01",
"orderStatus": "Completed",
"orderPayTime": 1690794182000,
"chainType": "ETH",
"externalOrderId": "622257420681202921",
"tokenType": "USDT",
"addressTo": "0xa8666442fA7583F783a169CC9F5449ec660295E8"
}
Callback Field Description
Parameter Name | Type | Description |
---|---|---|
orderAmount | String | Order amount |
orderTime | int64 | Order creation time (Unix timestamp in ms) |
orderId | String | Platform order ID |
orderStatusCode | int64 | Order status code (see explanation below) |
tradeHash | String | Blockchain transaction hash |
orderFee | String | Transaction fee amount |
orderStatus | String | Order status description (e.g., Completed) |
orderPayTime | int64 | Payment completion time (Unix timestamp in ms) |
chainType | String | Blockchain main chain type (e.g., ETH) |
externalOrderId | String | Merchant order ID |
tokenType | String | Cryptocurrency type (e.g., USDT) |
addressTo | String | Receiving address |
Order Status Code Description (orderStatusCode)
Status Code | Description |
---|---|
1 | Accepted: Order has been accepted, awaiting processing |
2 | Completed: Payment successful, the platform will automatically send the callback notification |
4 | Payment Failed: Payment could not be completed |
8 | Pending Approval: Payment is awaiting approval |
16 | Payment Rejected: The payment has been rejected |
⚠️ Callback Handling Recommendations
- Once
orderStatusCode == 2
and the signature verification is successful, the payment is confirmed as completed. Proceed with crediting / shipment / status update operations. - Callback notifications may be resent, so ensure idempotent processing.
- If a non-200 response or signature verification failure occurs, the platform will retry the callback.
Manual Callback Explanation
Merchants can manually trigger a callback in the backend order management system. Please note the following:
- It is not recommended to trigger manual callbacks for orders that are not in a final state, such as "Accepted", "Pending Approval", etc.
- If a manual callback is triggered but the order is not yet in a final state, the platform will resend the callback when the order's status changes to a final state. Merchants should ensure proper deduplication at the business layer.
# Callback Response
Description
- All callbacks include a signature field. It is recommended that merchants validate the callback to ensure the integrity of the callback data.
- After receiving and processing the callback data, merchants must respond to the gateway with the following JSON format:
Example Response (Success)
{
"code": 200,
"success": true
}
Callback Retries Mechanism (Important) 🔥
To ensure stable delivery and business consistency of the callback notifications, the platform has designed a retry strategy. If the merchant system fails to respond to the callback (e.g., network timeout, returns a non-200 status code, etc.), the system will retry according to the following rules:
Callback Retry Schedule (4 attempts total):
Attempt No. | Interval (approx.) | Description |
---|---|---|
1st Attempt | About 2 minutes | First retry after initial failure |
2nd Attempt | About 2 minutes | Second retry after first failure |
3rd Attempt | About 11 minutes | Third retry after second failure |
4th Attempt | About 2 minutes | Final retry after third failure |
Note: The intervals above represent internal scheduling intervals. The "callback time" recorded in the merchant's backend includes the merchant's processing/response time, so there may be a slight discrepancy (about 1 minute) between the displayed and actual push times.
Practical Reminders
- When there is a large volume of orders online, callbacks may experience queue delays, so please ensure the server can handle high concurrency.
- Each callback is an idempotent operation, and merchants should support idempotent checks.
- After 4 failed retry attempts, the system will stop retrying automatically, and it is recommended to manually trigger the callback via the backend.
Callback Response Parameters
Param | Type | Required | Description |
---|---|---|---|
code | int | ✅ | Status code; 200 for success |
success | boolean | ✅ | Whether the response was successful |
# Callback Notification URL Configuration
Two types of notification address configurations are supported:
- [Merchant Backend] Configure a Unified Callback Address
This can be configured in the "Merchant Backend" → "Developer Center."
Suitable for handling callbacks with common logic across most orders.
2.Order-level Manual Specification of Callback URL (notifyUrl)
- The
notifyUrl
field can be passed when creating an order. - If the order specifies the
notifyUrl
parameter, the system will use that address as the only callback notification target.
Priority of Address Configuration
The notifyUrl
in the order takes precedence over the unified callback address configured in the system.
Priority of Response Status Code
The platform uses the HTTP response status code (status_code
) as the only criterion to determine whether the callback was successful.
Specific Rules:
- ✅ As long as the merchant system returns
HTTP 200
, the platform will consider the callback as successful.- In this case, even if the returned content is not
{ "code": 200, "success": true }
, it will be ignored.
- In this case, even if the returned content is not
- ❌ If the response
status_code ≠ 200
(e.g., 400/500) or there is no response, the callback will be considered failed, and the platform will automatically retry the push.