跳至主要内容

Payment Notify

Authentication

  • Share the IP whitelist with each other;
  • Bybit Pay will encrypt the callbacks via RSA_SHA256. Partners can provide the public key, sign date put in result head. For details, please see Signature Algorithm

HTTP Request

Method: POST
URL: provide the callback url in the Create Payment request parameter webhookUrl

ParameterComments
Content-Typeapplication/json
VersionAPI version (e.g., "5.00", "5.01"). Matches the version used when creating the order.
timestampCurrent timestamp (Unix seconds, 10 digits)
publicKeyMerchant's RSA public key (optional, used for webhook signature verification)
signatureGenerated by Signature Algorithm
Timestamp Format

All timestamp fields in webhook callbacks use Unix timestamp in seconds (10 digits):

  • Header timestamp: 1736236800 (seconds since epoch)
  • Body fields (createTime, paymentTime, finishTime): 1736233200 (seconds since epoch)

Important: When verifying the signature, use the timestamp values exactly as they appear in the JSON body. Do NOT multiply by 1000.

Callback Request Parameters

ParameterTypeComments
paymentTypestringPayment type
  • E_COMMERCE: Bybit QR Pay for e-commerce
  • E_COMMERCE_REFUND: Bybit QR Pay refund for e-commerce
  • <PayOrderType>Returned when "paymentType"=E_COMMERCE
    <RefundOrderType>Returned when "paymentType"=E_COMMERCE_REFUND

    Signature Algorithm

    Signature Method

    Bybit Pay webhook uses JSON body for signature calculation. The signature string is constructed by concatenating:

    timestamp + JSON_body

    Where:

    • timestamp: Current Unix timestamp in seconds (10 digits)
    • JSON_body: Complete JSON request body as a string (no sorting, no conversion)

    Important: Do NOT convert the JSON to URL-encoded format. Use the raw JSON string directly.

    Sign (Bybit Pay Platform)

    1. Generate current timestamp (Unix seconds): timestamp = 1736236800
    2. Marshal the callback data to JSON string (preserve field order as-is)
    3. Concatenate: signContent = timestamp + jsonString
      1736236800{"paymentType":"E_COMMERCE","merchantId":"305142568",...}
    4. Encrypt with SHA256 and sign with RSA (PKCS1v15, 1024-bit key)
    5. Encode the signature bytes in base64

    Verify (Merchant Side)

    1. Get timestamp and signature from request headers
    2. Read the raw request body as string (do not parse yet)
    3. Concatenate: signContent = timestamp + requestBody
      1736236800{"paymentType":"E_COMMERCE","merchantId":"305142568",...}
    4. Decode the signature from base64
    5. Verify the signature using SHA256 and Bybit's RSA public key

    Example: Sign & Verify

    For example, we sign the following data. The timestamp is 1736236800, the RSA key is

    -----The following key pairs are for testing only-----
    -----BEGIN RSA PUBLIC KEY-----
    MIGJAoGBAOFSnhqtu40TOtok+yXeB+O76PXb/VAJU4Yih6hViOdSGd7imWmCSZyP
    psl3TmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXf+AxlKYMj8OQ
    AgDPmZG1a5ydFrje4PLytC7sUw3GP4TTk8xg6iMHmYPdRDv7AEWdAgMBAAE=
    -----END RSA PUBLIC KEY-----

    -----BEGIN RSA PRIVATE KEY-----
    MIICXwIBAAKBgQDhUp4arbuNEzraJPsl3gfju+j12/1QCVOGIoeoVYjnUhne4plp
    gkmcj6bJd05i4VKAfq082AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    DI/DkAIAz5mRtWucnRa43XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    AoGBAIqpeCi83516xw32XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    axzIwyfWTTATWbiCS9sqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    6gOQYu8kzRqCzqvyMNdAHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    e/Gxi7qhuIKz0mvfA/yieXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    3IBIdV/CbwJBAOQcsOPf+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    /5V9zdim+hPq+9cvsqO7dXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    MY4uV8noiqDRf/pvAkyMMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    15eWR4jEoXMIFkd7Onc6tXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Bnj6KW1fk+UM29dUDjmTqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    IavMyjrhDKyBGZ0mI6eoREaC4bxl31RRkYtg9mNeU3TxsBM=
    -----END RSA PRIVATE KEY-----

    JSON Payload Example:

    {
    "paymentType": "E_COMMERCE",
    "merchantId": "305142568",
    "clientId": "client_001",
    "merchantTradeNo": "af8c2d1-5b3e-4a9f-b6c7-8d2e1f3a4b5c",
    "payId": "01JY2KM5QNPXR8S4HTJZT9BC12",
    "status": "PAY_SUCCESS",
    "amount": "100",
    "currency": "USDT",
    "currencyType": "crypto",
    "createTime": 1736233200,
    "paymentTime": 1736233260,
    "finishTime": 1736233260
    }

    Signature Calculation Steps:

    1. Generate timestamp: 1736236800
    2. Convert JSON to string (minified, no extra spaces):
      {"paymentType":"E_COMMERCE","merchantId":"305142568","clientId":"client_001","merchantTradeNo":"af8c2d1-5b3e-4a9f-b6c7-8d2e1f3a4b5c","payId":"01JY2KM5QNPXR8S4HTJZT9BC12","status":"PAY_SUCCESS","amount":"100","currency":"USDT","currencyType":"crypto","createTime":1736233200,"paymentTime":1736233260,"finishTime":1736233260}
    3. Concatenate: signContent = timestamp + jsonString
      1736236800{"paymentType":"E_COMMERCE","merchantId":"305142568",...}
    4. Sign with SHA256 + RSA private key
    5. Encode to base64:
      NgDZLZCVBdma904hzZXmU+fQ7dr7z7muZkuwAbDnibLXXXXXXXXXXXXgmzad58LfRtLXGlkNPXXXXXXXXXXX9jNYd6gxp7j0Mlh0vQlQCIb2283DQ3wbZDphilvXXXXXXXXXXXXX2IIBelYBBw39U=

    Verification Steps (Merchant Side):

    1. Extract timestamp and signature from request headers
    2. Read raw request body (string, do not parse)
    3. Concatenate: signContent = timestamp + requestBody
    4. Decode signature from base64
    5. Verify using SHA256 + RSA public key

    Test Keys:

    -----The following key pairs are for testing only-----
    -----BEGIN RSA PUBLIC KEY-----
    MIGJAoGBAOFSnhqtu40TOtok+yXeB+O76PXb/VAJU4Yih6hViOdSGd7imWmCSZyP
    psl3TmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXf+AxlKYMj8OQ
    AgDPmZG1a5ydFrje4PLytC7sUw3GP4TTk8xg6iMHmYPdRDv7AEWdAgMBAAE=
    -----END RSA PUBLIC KEY-----

    -----BEGIN RSA PRIVATE KEY-----
    MIICXwIBAAKBgQDhUp4arbuNEzraJPsl3gfju+j12/1QCVOGIoeoVYjnUhne4plp
    gkmcj6bJd05i4VKAfq082AXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    DI/DkAIAz5mRtWucnRa43XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    AoGBAIqpeCi83516xw32XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    axzIwyfWTTATWbiCS9sqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    6gOQYu8kzRqCzqvyMNdAHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    e/Gxi7qhuIKz0mvfA/yieXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    3IBIdV/CbwJBAOQcsOPf+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    /5V9zdim+hPq+9cvsqO7dXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    MY4uV8noiqDRf/pvAkyMMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    15eWR4jEoXMIFkd7Onc6tXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Bnj6KW1fk+UM29dUDjmTqXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    IavMyjrhDKyBGZ0mI6eoREaC4bxl31RRkYtg9mNeU3TxsBM=
    -----END RSA PRIVATE KEY-----

    Request Example

    Callback Pay Order (Payment Success)

    POST ${webhook url} HTTP/1.1
    Host: www.merchant.com
    timestamp: 1736233260
    signature: NgDZLZCVBdma904hzZXmU+fQ7dr7z7muZkuwAbDnibLXXXXXXXXXXXXgmzad58Lf...
    Content-Type: application/json

    {
    "paymentType": "E_COMMERCE",
    "merchantId": "305142568",
    "clientId": "client_001",
    "merchantTradeNo": "af8c2d1-5b3e-4a9f-b6c7-8d2e1f3a4b5c",
    "payId": "01JY2KM5QNPXR8S4HTJZT9BC12",
    "status": "PAY_SUCCESS",
    "amount": "100",
    "currency": "USDT",
    "currencyType": "crypto",
    "createTime": 1736233200,
    "paymentTime": 1736233260,
    "finishTime": 1736233260,
    "customer": {
    "uid": "104326789",
    "externalUserId": "user123@merchant.com",
    "userName": "John Doe",
    "registerTime": 1704067200,
    "kycCountry": "USA"
    }
    }

    Callback Pay Order (Payment Failed)

    POST ${webhook url} HTTP/1.1
    Host: www.merchant.com
    timestamp: 1736233500
    signature: NgDZLZCVBdma904hzZXmU+fQ7dr7z7muZkuwAbDnibLXXXXXXXXXXXXgmzad58Lf...
    Content-Type: application/json

    {
    "paymentType": "E_COMMERCE",
    "merchantId": "305142568",
    "clientId": "client_001",
    "merchantTradeNo": "bf9d3e2-6c4f-5b0g-c8d9-9e3f2g4b6d7e",
    "payId": "01JY2KM5QNPXR8S4HTJZT9BC13",
    "status": "PAY_FAILED",
    "amount": "50",
    "currency": "USDT",
    "currencyType": "crypto",
    "createTime": 1736233300,
    "paymentTime": 0,
    "finishTime": 1736233500,
    "customer": {
    "uid": "104326790",
    "externalUserId": "user456@merchant.com",
    "userName": "Jane Smith",
    "registerTime": 1709251200,
    "kycCountry": "GBR"
    }
    }

    Callback Refund Order

    POST ${webhook url} HTTP/1.1
    Host: www.merchant.com
    timestamp: 1736234000
    signature: NgDZLZCVBdma904hzZXmU+fQ7dr7z7muZkuwAbDnibLXXXXXXXXXXXXgmzad58Lf...
    Content-Type: application/json

    {
    "paymentType": "E_COMMERCE_REFUND",
    "refundId": "RF01JY2KM5QNPXR8S4HTJZT9BC14",
    "refundType": "MERCHNT_SELF_REFUND",
    "merchantTradeNo": "af8c2d1-5b3e-4a9f-b6c7-8d2e1f3a4b5c",
    "merchantRefundNo": "RF-2026-0001",
    "payId": "01JY2KM5QNPXR8S4HTJZT9BC12",
    "refundStatus": "REFUND_SUCCESS",
    "refundCurrency": "USDT",
    "amount": "50",
    "createTime": 1736234000
    }

    Callback Broker Prefund Order

    Broker Prefund Feature

    This webhook is triggered for broker prefund orders (payment type: BROKER_PREFUND). It notifies merchants about cryptocurrency exchange/conversion order status updates.

    Use Case: When a merchant processes a fiat-to-crypto or crypto-to-fiat conversion through Bybit's broker service.

    POST ${webhook url} HTTP/1.1
    Host: www.merchant.com
    Version: 5.01
    timestamp: 1736235000
    signature: NgDZLZCVBdma904hzZXmU+fQ7dr7z7muZkuwAbDnibLXXXXXXXXXXXXgmzad58Lf...
    Content-Type: application/json

    {
    "tradeNo": "DL202601280001",
    "status": "completed",
    "quoteTxId": "QUOTE-20260128-001",
    "exchangeRate": "1.0025",
    "fromCoin": "USD",
    "fromCoinType": "fiat",
    "toCoin": "USDT",
    "toCoinType": "crypto",
    "fromAmount": "1000.00",
    "toAmount": "998.75",
    "createdAt": "1736235000000",
    "subUserid": "12345678"
    }

    Broker Prefund Order Fields:

    FieldTypeDescription
    tradeNostringBroker deal order ID
    statusstringOrder status: pending, completed, failed, cancelled
    quoteTxIdstringQuote transaction ID (price lock ID)
    exchangeRatestringExchange rate applied (unit price)
    fromCoinstringSource currency/coin
    fromCoinTypestringSource currency type: fiat or crypto
    toCoinstringDestination currency/coin
    toCoinTypestringDestination currency type: fiat or crypto
    fromAmountstringSource amount (how much user pays)
    toAmountstringDestination amount (how much user receives)
    createdAtstringOrder creation timestamp in milliseconds (13 digits)
    subUseridstringSub-user ID (slave UID)

    Status Values:

    • pending: Order is being processed
    • completed: Order completed successfully
    • failed: Order failed
    • cancelled: Order was cancelled

    Note: Unlike payment orders, the createdAt field in broker prefund orders uses milliseconds (13 digits), not seconds.