logo

Search...

⌘ K

English

Product Guide
API Reference
Resource Download
Help Center

Getting Started

Overview

Scenario Capabilities

Onboarding Steps

Payin Capabilities

CKP Checkout Page

Interaction

Integration Prep

Integration Steps

Deeplink Redirect

Interaction

Integration Prep

Integration Steps

QRCode Display

Interaction

Integration Prep

Integration Steps

Payout Capabilities

Capability Overview

Deposit

Crypto Withdraw / Payout

Fiat Withdraw

Receive Payout Result

Supported Chains and Currencies

Supported Chains

Supported Currencies

Appendix

Wallets / Currencies / Chains

Transaction Status

Payment Status

Refund Status

Withdraw Status

Batch Status

Error Code Description

Signature Algorithm

Receive Payout Result

Paydify calls back the Partner to implement the related business process.

Withdrawal Notification

  • URL: the payout callback URL of your app (configured by Paydify for the app, not passed per order; contact Paydify to set or change it)
  • Method: POST
  • Content-Type: application/json
  • Trigger: pushed when a withdraw order reaches a terminal state (SUCCESS / FAILED), exactly once per withdraw. Every detail of a batch withdraw is also notified one by one through this callback; batch-level status is pull-only via Batch Withdraw Query

See the API reference Withdraw Notification for the full field definitions.

Callback Headers

Header Required Description
content-type Yes Always application/json
x-api-key Yes Your appId
x-api-timestamp Yes Unix timestamp in milliseconds
x-api-signature Yes Signature generated by Paydify

Callback Body

Field Name Type Required Description
appId string Yes appId of the app the order belongs to
withdrawId string Yes Paydify withdraw order ID
mchWithdrawId string Yes Merchant withdraw order ID (the mchWithdrawId passed at apply)
status string Yes Withdraw status; only terminal states are pushed: SUCCESS (on-chain transfer and settlement succeeded) / FAILED (funds returned to balance, see errorMsg)
currency string Yes Withdraw currency
network string Yes Chain network
amount string Yes Withdraw amount, 0 when absent
gasFee string Yes On-chain gas fee, 0 when absent
processingFee string Yes Processing fee, 0 when absent
address string Yes Destination address
txnHash string No On-chain transaction hash, present when available
finishedTime long Yes Completion timestamp in milliseconds, 0 when absent
errorCode string No Error code, may be present only on failure
errorMsg string No Failure reason, may be present only on failure

Example

{
  "appId": "A123456788",
  "withdrawId": "W5081643613805694001",
  "mchWithdrawId": "PAYOUT_20260610_001",
  "status": "SUCCESS",
  "currency": "USDT",
  "network": "TRON",
  "amount": "99.99000000",
  "gasFee": "0.01000000",
  "processingFee": "0.5",
  "address": "TX7dEjrN...",
  "txnHash": "0xabcdef...",
  "finishedTime": 1780971800000
}

Fiat Withdrawal Notification

  • URL: the callback URL of your fiat withdraw app config (configured by Paydify for the app, not passed per order)
  • Method: POST
  • Content-Type: application/json
  • Trigger: pushed when a fiat withdraw order reaches a terminal state (COMPLETED / FAILED / CANCELLED / REJECTED); non-terminal states (PENDING / PROCESSING / SETTLING, etc.) are not pushed, exactly once per withdraw

Key fields: withdrawId (Paydify fiat withdraw order ID), mchWithdrawId (the mchOrderId passed at apply), status, orderAmount (arrival amount, currently in USD), amount (total deducted amount), withdrawFeeAmount (fee), quoteId, deductionSnapshot / bankAccountSnapshot (snapshots as JSON strings), finishedTime, errorMsg. See the API reference Fiat Withdraw Notification for the full field definitions.

Callbacks share the same signature mechanism as Payin. If no callback arrives for a long time, query proactively via /withdraw/detail or /fiat-withdraw/detail. For orders created with a partner credential, the callback signature is computed with the ordering credential apiSecret, while x-api-key remains the appId of the app the order belongs to.

Callback Response

Acknowledge with HTTP 200 and the plain text success (case-insensitive):

Response Value Description
success Callback acknowledged successfully
Anything else Treated as failure and triggers re-push (including fail, JSON objects, HTML error pages, and empty bodies)

Callback Signature Verification

Use your secretKey to verify the callback before processing the business logic.

The signed content contains exactly these fields:

Field Value
apiPath The path part of your webhook URL, for example /api/payout/webhook
body The exact raw request body string
x-api-key The value from the request header
x-api-timestamp The value from the request header

Verification rules:

  1. Use HMAC-SHA256
  2. Sort the field names in ascending order before JSON serialization
  3. JSON serialize the sorted content map
  4. Base64 encode the HMAC result
  5. Compare the generated value with x-api-signature
  6. Use the request path only; do not include scheme, domain, or query parameters
  7. Use the raw request body exactly as received; do not parse and rebuild it before verification

In practice, the object to be signed should look like this (the body below is truncated to two fields for illustration — it is not a complete callback payload; always sign against the complete raw request body string you received):

{
  "apiPath": "/api/payout/webhook",
  "body": "{\"withdrawId\":\"W5081643613805694001\",\"mchWithdrawId\":\"PAYOUT_20260610_001\"}",
  "x-api-key": "A123456788",
  "x-api-timestamp": "1762513487000"
}

Final signature:

Base64(HMAC_SHA256(jsonString, secretKey))
  1. Read x-api-key, x-api-timestamp, and x-api-signature from the headers
  2. Read the raw request body as a UTF-8 string
  3. Get the request path only, for example /api/payout/webhook
  4. Build the content map with apiPath, body, x-api-key, and x-api-timestamp
  5. Sort the keys in ascending order
  6. JSON serialize the sorted map
  7. Compute HMAC-SHA256 using your secretKey
  8. Base64 encode the result
  9. Compare the generated value with x-api-signature
  10. Process the webhook only after the signature matches

Node.js Example

const crypto = require("crypto");

function verifyPaydifyWebhook({
  path,
  rawBody,
  apiKey,
  timestamp,
  receivedSignature,
  secretKey,
}) {
  const content = {
    apiPath: path,
    body: rawBody || "",
    "x-api-key": apiKey,
    "x-api-timestamp": String(timestamp),
  };

  const jsonString = JSON.stringify(content);

  const expectedSignature = crypto
    .createHmac("sha256", secretKey)
    .update(jsonString, "utf8")
    .digest("base64");

  return expectedSignature === receivedSignature;
}

Common Verification Failures

  • Using plain SHA256 instead of HMAC-SHA256
  • Rebuilding the JSON body before verification
  • Using the full URL instead of the path only
  • Including query parameters in the signature calculation
  • Using a different timestamp value from the header
  • Comparing hex output with a Base64 signature

Callback Retry Mechanism

If the callback does not receive the expected response value success, it will be re-pushed at intervals of 15s / 45s / 90s / 180s / 10m / 30m / 60m / 3h / 6h / 12h, up to 11 attempts including the first push:

Request Number Time Delay Description
1 0 First callback, executed right after the terminal state is persisted
2 15 seconds 1st retry
3 45 seconds 2nd retry
4 90 seconds 3rd retry
5 180 seconds 4th retry
6 10 minutes 5th retry
7 30 minutes 6th retry
8 60 minutes 7th retry
9 3 hours 8th retry
10 6 hours 9th retry
11 12 hours 10th retry; delivery stops if it still fails

Catalogue