Integration GuideAPI Reference
Integration Guide

Bybit Pay - Payments

📓

Payment Method Name

Set payments[].paymentInstrument.paymentMethodName to ByBitPay when creating an Intent: "paymentMethodName": "ByBitPay"

📘

Bybit Pay lets your customers pay by scanning a QR code with Bybit. In the H2H flow, you create an Intent with a Payment, receive the QR image in the synchronous response, and display it on your checkout page. The payer scans the QR, reviews the transaction details, and confirms the payment in Bybit. Configure a webhook URL in the request or in your settlement account settings to receive status updates.

Payment Method Features

Payment MethodVietQR
Country--
Processing CurrenciesUSDT
PaymentsYes
DisbursementsYes
RefundsYes
ChargebacksNo

Workflow: Payment


📘

In step 1.7, display the QR from payments[].additionalData.details.qrBase64 on your checkout page.

incomingDetails.redirectUrl and incomingDetails.failureUrl are the payer's return destinations after the payment attempt. Payment status notifications use the webhook URL configured for the payment or its settlement account.

Possible Payment Scenarios

ScenarioSteps
QR creation[1.1] The payer chooses Bybit Pay on your checkout page.
[1.2] You send POST /processing/api/v1/intents with a Bybit Pay payment.
[1.3] Our platform creates the Intent and Payment.
[1.4–1.5] Our platform creates the Bybit order and obtains its QR.
[1.6] The synchronous response contains the created objects, payment status, and QR image.
[1.7] You display the QR to the payer. The payment awaits confirmation in AUTHORIZATION_REQUESTED.
Successful payment[2.1] The payer scans the QR in Bybit.
[2.2–2.4] Bybit displays the transaction details, the payer confirms the payment, and Bybit displays the result.
[2.5–2.6] Our platform receives the successful payment result and changes the payment status to CAPTURED.
[2.7] Our platform sends a webhook to the configured URL.
QR expiration[3.1] The payment session expires before the payer completes the payment.
[3.2] Our platform changes the payment status to CANCELLED.
[3.3] Our platform sends a webhook to the configured URL with the updated status.
📘

Use the payment status received from our platform to confirm the result. Returning the payer to redirectUrl or failureUrl is part of the browser flow and does not replace a payment status notification.

Stop displaying the QR when the payment session expires or the payment reaches a final status. If a result notification is unavailable, retrieve the current payment status.

List of Used API Requests

RequestEndpointDescription
Intent creationPOST /processing/api/v1/intentsCreates an Intent with a Bybit Pay Payment and returns the QR when creation succeeds.
Refund creationPOST /processing/api/v1/refundsCreates a refund for an existing payment in CAPTURED status.
Payment statusGET /processing/api/v1/payments/{id}Retrieves the payment and its current status. Use the platform payment ID.
Refund statusGET /processing/api/v1/refunds/{id}Retrieves the refund and its current status. Use the platform refund ID.

Use the standard platform authentication and settlement-account-id header described in the API reference. The examples below show JSON request and response bodies.

Intent Creation Request/Response

📓

Request specifics

  • Endpoint: POST /processing/api/v1/intents.
  • Payment method: ByBitPay.
  • Method-specific data: payments[].paymentInstrument.incomingDetails.
  • Required incoming details: redirectUrl, failureUrl, terminalType, device, browserVersion, and ip.
  • Optional incoming detail: sessionTimeoutMin.

Intent Request: Template

CURRENCY_CODE is a placeholder: replace it with the currency enabled for your integration. This example uses the same submitted and authorisation currency. The sample amount is illustrative.

{
  "clientReferenceId": "order-bybit-1001",
  "useCheckoutForm": false,
  "payments": [
    {
      "paymentInstrument": {
        "paymentMethodName": "ByBitPay",
        "incomingDetails": {
          "sessionTimeoutMin": 20,
          "redirectUrl": "https://merchant.example.com/payments/success",
          "failureUrl": "https://merchant.example.com/payments/failure",
          "terminalType": "WEB",
          "device": "checkout-device-01",
          "browserVersion": "Chrome/133.0.0.0",
          "ip": "203.0.113.10"
        }
      },
      "submittedAmount": {
        "value": 100.50,
        "currency": "USDT"
      },
      "authCurrencyCode": "USDT",
      "webhookUrl": "https://merchant.example.com/webhooks/payments"
    }
  ]
}

Intent Request: Fields Description

Top-Level Request Parameters
ParameterTypeRequiredDescription
clientReferenceIdStringRequiredYour reference for the intent, such as an order number.
paymentsArray of ObjectsRequiredPayments to create within the intent. Include the Bybit Pay payment in this array.
useCheckoutFormBooleanOptionalSet to false for this H2H flow. Defaults to false.
descriptionStringOptionalIntent description. In the sandbox, use this top-level field to select an emulator scenario. See Testing in Sandbox.
payment — payments[]
ParameterTypeRequiredDescription
paymentInstrumentObjectRequiredPayment method and its incoming details.
submittedAmountObjectRequiredPayment amount and currency submitted to the platform.
authCurrencyCodeStringRequiredCurrency used to authorise the payment. Use a currency enabled for your integration. If no currency conversion is needed, use the same value as submittedAmount.currency.
webhookUrlStringOptionalHTTPS endpoint for this payment's status updates. Overrides the settlement account's default webhook URL. If omitted, the account default is used. Configure either URL to receive notifications.
payerObjectOptionalPayer details, if supplied. See the common Intent API reference for the object schema.
descriptionStringOptionalDescription of this payment. The sandbox scenario keyword belongs in the top-level intent description.
billingAddressObjectOptionalPayer billing address, using the common API schema.
totalTaxAmountObjectOptionalTax amount included in the payment, using the common monetary amount schema.
paymentInstrument
ParameterTypeRequiredDescription
paymentMethodNameStringRequiredSet to ByBitPay.
incomingDetailsObjectRequiredBybit Pay details listed below.
incomingDetails

Full path: payments[].paymentInstrument.incomingDetails.

ParameterTypeRequiredDescription
sessionTimeoutMinIntegerOptionalPayment session lifetime in minutes.
redirectUrlStringRequiredURL to return the payer to after a successful payment.
failureUrlStringRequiredURL to return the payer to after a failed payment.
terminalTypeStringRequiredTransaction source: APP, WEB, WAP, MINIAPP, or OTHERS.
deviceStringRequiredIdentifier of the payer's device.
browserVersionStringRequiredBrowser or application version information for the payer's environment.
ipStringRequiredPayer IP address.
submittedAmount
ParameterTypeRequiredDescription
valueNumberRequiredPayment amount as a JSON number, for example 100.50. Use a decimal point as the separator.
currencyStringRequiredSubmitted currency code. Use a currency enabled for your integration.

Payment Statuses

StatusMeaning
AUTHORIZATION_REQUESTEDThe payment has been initiated and awaits completion. In the successful QR creation flow, the QR is available for display.
CAPTUREDPayment completed successfully. Final payment status.
DECLINEDPayment was declined. Final payment status. See the sandbox scenario for a simulated decline.
CANCELLEDThe payment session expired before completion. Final payment status for the expiration scenario.
ERRORPayment processing failed. In the LinkCreationError sandbox scenario, this status is returned synchronously and no usable QR is created.

Webhooks

Our platform sends transaction status updates using the following URL selection:

  1. The webhookUrl supplied for the payment or refund.
  2. If that field is omitted, the default webhook URL configured for the settlement account.

If neither URL is configured, no webhook is sent. A refund's URL is resolved independently of the original payment's URL.

Webhooks use HTTPS POST requests with a JSON body. Acknowledge receipt with an HTTP 2xx response. See Webhooks: Overview for delivery rules and Webhooks: Example for payloads.

TransactionOptional URL overrideOutcomes described on this page
Paymentpayments[].webhookUrl in the intent creation requestCAPTURED, DECLINED, CANCELLED, or a processing ERROR.
RefundwebhookUrl in the refund creation requestREFUNDED, DECLINED, or a technical ERROR.

Use the transaction identifier and status in the webhook to update your records. Payment and refund statuses belong to their respective transactions. The table lists the outcomes covered here; it is not an exhaustive list of notifications. Handle intermediate updates according to the common webhook contract.

If you do not receive a result notification, retrieve the current payment or refund by its platform ID. A missing webhook does not establish whether an operation succeeded or failed.

Workflow: Refunds

Create a refund for an existing Bybit Pay payment in CAPTURED status. The request references the original platform payment ID returned as payments[].id.

The diagram shows a request accepted for processing. Request validation failures are returned synchronously; see Refund Creation Errors below.

How It Works

StepWhat happens
1The payer asks you for a refund.
2You send a refund creation request with the original paymentId.
3Our platform validates the request and creates a separate Refund transaction.
4A successful HTTP 200 response with status = ACCEPTED confirms acceptance for processing.
5Our platform submits the refund request to Bybit.
6Bybit returns the refund result.
7Our platform records the refund result: REFUNDED or DECLINED. Technical processing failures can result in ERROR.
8Our platform sends the latest refund status to the configured webhook URL, if available.

Refund Request/Response

📓

Request specifics

  • Endpoint: POST /processing/api/v1/refunds.
  • Original transaction: a payment in CAPTURED status.
  • Example below: a full refund. Omit paymentSubmittedAmount and paymentAuthAmount to request the original payment amounts.
  • Existing successful or in-progress refunds reduce the amount available for refund. Omitting the amount fields requests the original amount, not just the remaining balance; the request must pass the available-amount checks.

Full Refund Request: Example

{
  "paymentId": 344115072812343296,
  "reason": "Customer requested a refund",
  "clientReferenceId": "order-bybit-1001-refund-1",
  "webhookUrl": "https://merchant.example.com/webhooks/refunds"
}

Full Refund Request: Fields Description

ParameterTypeRequiredDescription
paymentIdInteger (int64)RequiredOriginal platform payment identifier. Use the exact value of payments[].id from the intent creation response.
partialBooleanOptionalDefaults to false. Omit it or set it to false for the full refund example.
reasonStringOptionalReason for the refund.
clientReferenceIdStringOptionalYour reference for one logical refund, unique within the settlement account. If supplied, it must be non-empty and no longer than 2048 characters. Preserve the same value when retrying that refund.
webhookUrlStringOptionalHTTPS endpoint for this refund's status updates. Overrides the settlement account's default webhook URL. If omitted, the account default is used. Configure either URL to receive notifications.

paymentId is a JSON integer in the refund request, while it is returned as a string in responses. Preserve the identifier exactly: these int64 values can exceed the exact integer range of JavaScript Number.

Refund Statuses

StatusMeaning
ACCEPTEDThe platform accepted the refund request for processing.
REFUND_REQUESTEDRefund processing has been requested; a final result is pending.
REFUNDEDThe refund completed successfully. Final refund status.
DECLINEDThe refund was declined. Final refund status.
ERRORA technical error occurred while processing the refund. Final refund status in the platform.

Refund Creation Errors

A failed creation request does not have the successful response shown above. The common error response uses errorCode, failureMessage, and timestamp; see the Refund API reference for the schema.

HTTP statusMeaning
400Invalid refund request or refund creation failure.
404The original payment was not found or is unavailable to the caller.
409A duplicate refund reference or a conflict with another refund creation operation.

Retrying a Refund Request

Use one clientReferenceId per logical refund. If the HTTP response is lost or times out, preserve that reference when retrying the same refund. A refund already created with the same reference is rejected with HTTP 409; the original successful response is not replayed.

Check the existing refund before submitting a new logical refund. When its platform ID is known, use GET /processing/api/v1/refunds/{id}. A timeout or 409 alone does not establish the final refund result.

Testing in Sandbox

Use the Bybit Pay emulator to test your handling of QR creation, successful payments, declines, and expiration.

Set payments[].paymentInstrument.paymentMethodName to ByBitPay and provide the required incoming details as in the production request.

For the webhook-based tests below, provide payments[].webhookUrl or configure a default webhook URL for the settlement account.

Select a scenario through the top-level description in the intent creation request, referred to below as intent.description. For a scenario without a keyword, omit this field or send an empty string.

Bybit Pay Payment Test Flow


📘

The sandbox response returns the test payment link in payments[].additionalData.details.url. The QR in payments[].additionalData.details.qrBase64 encodes the same link.

Opening the URL triggers the scenario result. Open it directly, or scan the QR with a QR reader and open the decoded link. The sandbox QR opens the platform's emulator. Displaying the QR image alone does not complete the payment.

For the expiration scenario, leave the test link unopened and wait for the payment session to expire.

Sandbox Response: Relevant Fields

The following is the additionalData fragment of a sandbox payment returned with status = AUTHORIZATION_REQUESTED. SANDBOX_PAYMENT_URL and BASE64_ENCODED_PNG_QR_IMAGE are placeholders for values returned by the API.

{
  "details": {
    "url": "SANDBOX_PAYMENT_URL",
    "qrBase64": "BASE64_ENCODED_PNG_QR_IMAGE"
  }
}
FieldFormatHow to use
payments[].additionalData.details.urlString containing the complete emulator URL.Open the returned value as-is to trigger the selected scenario. Do not construct the URL or change its query parameters.
payments[].additionalData.details.qrBase64PNG image encoded as plain Base64, without a data URI prefix.Display the image. Scanning it yields the same URL as details.url. Opening that URL triggers the selected scenario.

Displaying the Sandbox QR in a Browser

For a returned payment object named payment and an HTML image element named qrImage:

qrImage.src =
  "data:image/png;base64," + payment.additionalData.details.qrBase64;

This displays the image only. Open payment.additionalData.details.url separately when you are ready to simulate the successful or declined payment.

List of Supported Cases

CaseScenario keyword (intent.description)ActionExpected payment status
Successful paymentNo keywordOpen payments[].additionalData.details.url before expiration.AUTHORIZATION_REQUESTEDCAPTURED
QR expiredNo keywordLeave the link unopened and wait for expiration.AUTHORIZATION_REQUESTEDCANCELLED
Payment declinedDeclinedPaymentOpen payments[].additionalData.details.url before expiration.AUTHORIZATION_REQUESTEDDECLINED
QR creation errorLinkCreationErrorSend the intent creation request.ERROR in the synchronous response.

Successful Payment

  1. Create an intent using the request template above, with no scenario keyword in the top-level description.
  2. Check that the response contains a payment in AUTHORIZATION_REQUESTED and a QR in payments[].additionalData.details.qrBase64.
  3. Display the QR on your checkout page and open payments[].additionalData.details.url before the session expires.
  4. Receive the payment status webhook and check that the payment status is CAPTURED.

Did this page help you?