Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.xpaylabs.com/llms.txt

Use this file to discover all available pages before exploring further.

XPayLabs sends HTTP POST callbacks to your configured endpoint URL whenever an order or collection changes state. Instead of polling the API for status changes, register your callback URL and receive signed notifications in real-time.

Configuration

Set your webhook endpoint URL and shared secret in the gateway configuration:
xpay:
  merchant:
    callback-url: "https://yourapp.com/webhooks/xpaylabs"
    webhook-secret: "your-webhook-secret-here"
The webhook-secret is used to compute the sign field in each webhook payload, allowing you to verify the notification originated from your gateway.

Payload Format

Every webhook callback is a POST request with a JSON body following the NotifyPayload structure:
FieldTypeDescription
signstringHMAC-SHA256 signature for payload verification
timestampintegerUnix timestamp of when the notification was generated
noncestringUnique event identifier
notifyTypestringThe event type (see Event Types)
dataobjectThe event payload (NotifyOrder object)

Example Payload

{
  "sign": "a1b2c3d4e5f6...",
  "timestamp": 1717000123,
  "nonce": "550e8400-e29b-41d4-a716-446655440000",
  "notifyType": "ORDER_SUCCESS",
  "data": {
    "orderId": "order_1042",
    "uid": "user_42",
    "orderType": "COLLECTION",
    "status": "SUCCESS",
    "reason": null,
    "amount": "250.00",
    "actualAmount": "249.50",
    "fee": "0.00",
    "transaction": {
      "chain": "TRON",
      "symbol": "USDT",
      "txid": "a1b2c3d4e5f6...",
      "from": "TXyz...",
      "to": "TWkKZkmuB8DpVeiMoHiKf99ZoFHzk73CqR",
      "amount": "250.00",
      "blockNum": 12345678,
      "confirmedNum": 3,
      "status": "SUCCESS",
      "timestamp": 1717000123
    }
  }
}

Signature Verification

Verify the webhook signature using your webhook-secret:

Algorithm

  1. Serialize the data object (the data field from the payload) as compact JSON.
  2. Compute HMAC-SHA256(data_json, webhook_secret).
  3. Convert to lowercase hex and compare with the sign field.

Node.js

import crypto from "crypto";

export function verifyWebhook(payload, secret) {
  const dataJson = JSON.stringify(payload.data);  // compact JSON
  const expectedSign = crypto
    .createHmac("sha256", secret)
    .update(dataJson, "utf8")
    .digest("hex");

  if (!crypto.timingSafeEqual(
    Buffer.from(expectedSign, "hex"),
    Buffer.from(payload.sign, "hex")
  )) {
    throw new Error("Invalid webhook signature");
  }

  return true;
}

// Express.js example
app.post("/webhooks/xpaylabs", express.json(), (req, res) => {
  try {
    verifyWebhook(req.body, process.env.XPAYLABS_WEBHOOK_SECRET);
  } catch (err) {
    return res.status(400).send("Verification failed");
  }

  const event = req.body;
  // Process event...
  res.status(200).send("ok");
});

Python

import hmac, hashlib, json
from flask import Flask, request

app = Flask(__name__)
WEBHOOK_SECRET = "your-webhook-secret"

@app.route("/webhooks/xpaylabs", methods=["POST"])
def handle_webhook():
    payload = request.get_json()
    data_json = json.dumps(payload["data"], separators=(",", ":"))
    expected_sign = hmac.new(
        WEBHOOK_SECRET.encode(),
        data_json.encode(),
        hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(expected_sign, payload["sign"]):
        return "Invalid signature", 400

    notify_type = payload["notifyType"]
    # Process event...
    return "", 200

Retry Policy

If your endpoint does not return a 2xx status code within 10 seconds, XPayLabs retries the webhook with exponential backoff:
AttemptDelay
1st retry~1 second
2nd retry~5 seconds
3rd retry~30 seconds
4th retry~5 minutes
After 4 failed attempts, the notification is marked as failed. Failed webhooks are logged and can be replayed from the gateway dashboard.

Best Practices

  • Respond immediately. Return 200 as fast as possible, then process the event asynchronously.
  • Verify every payload. Always check the HMAC signature before acting on a webhook.
  • Use nonce for deduplication. Store processed nonces to handle at-least-once delivery.
  • Check notifyType. Route events based on the notification type to handle each event correctly.