Every API request to XPayLabs must include a cryptographic signature. This page details the exact signing algorithm, the purpose of each field, and common pitfalls.
Signing Algorithm
The sign field is computed as:
Where:
data is the request body payload (the data field of ReqPayload)
merchant_token is your configured secret token
HMAC-SHA256 produces a binary digest
HEX converts it to a lowercase hexadecimal string (64 characters)
Important: JSON Serialization
The data object must be serialized to JSON with no extra whitespace. Different JSON libraries may produce different output:
| Library | Output | Valid? |
|---|
JSON.stringify(obj) | {"amount":"100.00","symbol":"USDT","chain":"TRON"} | ✅ Yes |
json.dumps(obj, separators=(",",":")) | {"amount":"100.00","symbol":"USDT","chain":"TRON"} | ✅ Yes |
json.dumps(obj, indent=2) | Formatted with spaces/newlines | ❌ No |
The signature is computed over the data field only — not over the full ReqPayload envelope. The sign, timestamp, and nonce fields are excluded from signing.
Request Envelope
Each request must include these four fields as a JSON object:
Language Examples
Node.js
Python
Java
Verification
XPayLabs verifies each request by:
- Recomputing the HMAC-SHA256 signature from the
data field and your stored merchant token.
- Checking that the computed signature matches the provided
sign value.
- Validating that the
timestamp is within 5 minutes of the server clock.
- Ensuring the
nonce has not been used before.
If any check fails, the gateway returns a 401 Unauthorized response:
GET Request Signing
For GET requests that require authentication (e.g., /v1/order/status/{orderId}, /v1/order/pay, /v1/order/getOrderStatus), the sign parameter is passed as a query string value. The signature is computed over the relevant parameters (typically orderId):