Skip to main content
Before reading this API documentation, be sure to review the API Description Guide
  • For credit card transactions, consumers maintain the right to initiate a dispute within 180 days of the charge date. When a dispute is filed, a dispute fee of $20 will be assessed per transaction.
  • Upon receiving a dispute notification, you have two options for response
    • First: you may accept the dispute by submitting a response to the issuing bank affirming that you do not contest the refunded amount.
    • Second, you may counter the dispute by completing a guided submission process that prompts you to provide relevant evidence and supporting documentation for your case.
  • Should you elect to counter a dispute, an additional dispute countered fee of $20 will be applied. In the event that the issuing bank does not accept your counter materials and rules in favor of the consumer, both the dispute countered fee will be deducted and the consumer’s payment will be refunded to them.
  • Regarding fee refunds, Haipay will return the dispute countered fee if you successfully win the dispute. However, unless explicitly stated otherwise in your Haipay contract, the initial dispute fee is non-refundable under all circumstances.
  1. PCI Compliance: Direct violation of PCI DSS requirements
  2. Security Risks: WebView and iframe may not provide sufficient security isolation
  3. Man-in-the-Middle Attacks: Malicious applications may intercept or tamper with payment data
  4. Phishing Risks: Cannot ensure users are entering sensitive information in a trusted environment

Device Environment Requirements

If you cannot see the wallet you want on the payment page, your device or browser may not meet the following Apple Pay or Google Pay requirements.
  • You must have at least one card in your wallet.
  • You must use compatible Apple Pay devices and Google Pay devices.
  • You must use HTTPS and supported browsers to test the wallet you are testing.
  • Allow applicable browsers to access your wallet.
    • Chrome: Settings > Autofill and passwords > Payment methods > Allow sites to check if you have saved payment methods
    • Safari: Settings > Advanced > Allow websites to check for Apple Pay and Apple Card
  • Do not use Chrome incognito window or Safari private window.
  • Confirm you are operating in supported Apple Pay and Google Pay regions.
  • For Apple Pay, confirm your device supports biometric authentication.
Desktop Browsers
  • Chrome 38+
  • Safari 10.1+
  • Firefox 29+
  • Edge 15+
  • Opera 25+
Mobile Browsers
  • iOS Safari 9+ and other browsers and web views using the system-provided WebKit engine
  • Android Chrome 38+
  • Samsung Browser 7.1+
Other NotesFor browsers not explicitly supported, we limit support as follows:
  • Requires browser support for TLS 1.2
  • Requires a sufficiently modern browser to support Promises in JavaScript
  • We respond to error reports but do not actively test other browsers

Regional Restrictions

AD - AndorraAE - United Arab EmiratesAF - AfghanistanAG - Antigua and BarbudaAI - AnguillaAL - AlbaniaAM - ArmeniaAO - AngolaAQ - AntarcticaAR - ArgentinaAS - American SamoaAW - ArubaAX - Åland IslandsBA - Bosnia and HerzegovinaBB - BarbadosBD - BangladeshBF - Burkina FasoBH - BahrainBI - BurundiBJ - BeninBL - Saint BarthélemyBM - BermudaBN - BruneiBQ - Bonaire, Sint Eustatius, and SabaBS - BahamasBT - BhutanBV - Bouvet IslandBW - BotswanaBY - BelarusBZ - BelizeCC - Cocos (Keeling) IslandsCD - Democratic Republic of the CongoCF - Central African RepublicCG - Republic of the CongoCI - Ivory CoastCK - Cook IslandsCM - CameroonCO - ColombiaCU - CubaCV - Cape VerdeCW - CuraçaoCX - Christmas IslandCY - CyprusDJ - DjiboutiDM - DominicaDO - Dominican RepublicDZ - AlgeriaEC - EcuadorEE - EstoniaEG - EgyptEH - Western SaharaER - EritreaET - EthiopiaFJ - FijiFK - Falkland IslandsFM - Federated States of MicronesiaFO - Faroe IslandsGA - GabonGD - GrenadaGE - GeorgiaGF - French GuianaGG - GuernseyGH - GhanaGI - GibraltarGL - GreenlandGM - GambiaGN - GuineaGP - GuadeloupeGQ - Equatorial GuineaGS - South Georgia and the South Sandwich IslandsGT - GuatemalaGW - Guinea-BissauHK - Hong KongHM - Heard Island and McDonald IslandsHN - HondurasHT - HaitiID - IndonesiaIL - IsraelIM - Isle of ManIN - IndiaIO - British Indian Ocean TerritoryIQ - IraqIR - IranJM - JamaicaJO - JordanJP - JapanKE - KenyaKH - CambodiaKI - KiribatiKM - ComorosKN - Saint Kitts and NevisKP - North KoreaKR - South KoreaKW - KuwaitKY - Cayman IslandsKZ - KazakhstanLA - LaosLB - LebanonLC - Saint LuciaLI - LiechtensteinLK - Sri LankaLR - LiberiaLS - LesothoLV - LatviaLY - LibyaMD - MoldovaME - MontenegroMF - Saint Martin (French part)MG - MadagascarMH - Marshall IslandsMK - North MacedoniaML - MaliMM - MyanmarMN - MongoliaMP - Northern Mariana IslandsMQ - MartiniqueMR - MauritaniaMS - MontserratMU - MauritiusMV - MaldivesMW - MalawiMY - MalaysiaMZ - MozambiqueNA - NamibiaNC - New CaledoniaNE - NigerNF - Norfolk IslandNG - NigeriaNI - NicaraguaNP - NepalNR - NauruNU - NiueOM - OmanPA - PanamaPE - PeruPF - French PolynesiaPG - Papua New GuineaPH - PhilippinesPK - PakistanPM - Saint Pierre and MiquelonPN - Pitcairn IslandsPR - Puerto RicoPS - PalestinePW - PalauRE - RéunionRU - RussiaRW - RwandaSA - Saudi ArabiaSB - Solomon IslandsSC - SeychellesSD - SudanSH - Saint HelenaSJ - Svalbard and Jan MayenSK - SlovakiaSL - Sierra LeoneSM - San MarinoSN - SenegalSO - SomaliaSR - SurinameSS - South SudanST - São Tomé and PríncipeSV - El SalvadorSX - Sint Maarten (Dutch part)SY - SyriaSZ - EswatiniTC - Turks and Caicos IslandsTD - ChadTF - French Southern TerritoriesTG - TogoTH - ThailandTK - TokelauTL - East TimorTM - TurkmenistanTN - TunisiaTO - TongaTR - TurkeyTT - Trinidad and TobagoTV - TuvaluTW - TaiwanTZ - TanzaniaUA - UkraineUG - UgandaUM - United States Minor Outlying IslandsUY - UruguayUZ - UzbekistanVA - Vatican CityVC - Saint Vincent and the GrenadinesVE - VenezuelaVG - British Virgin IslandsVI - U.S. Virgin IslandsVN - VietnamVU - VanuatuWF - Wallis and FutunaWS - SamoaYE - YemenYT - MayotteZA - South AfricaZM - ZambiaZW - Zimbabwe

HaiPay.js Integration (Apple Pay & Google Pay)

HaiPay provides a convenient Apple Pay and Google Pay payment integration solution that allows you to quickly integrate payment functionality into web pages through simple configuration.
<script src="https://cashier.haipay.top/js/applePayGooglePay_1.0.0.min.js"></script>

<div>
  <div id="applePay-googlePay"></div>
</div>

  // Create instance
  const elements = applePayGooglePay.create('applePayGooglePay', {
      sandbox: true,
      clientToken: '6cgjnxvc6kdb',
      buttonType: 'buy',
      buttonTheme: 'black',
      buttonHeight: 50
  });

  // Mount component
  elements.mount('#applePay-googlePay');

 // Payment button render completion callback
  elements.on('ready', (data) => {
      console.log('Button rendered successfully:', data);
  });

 // Error message
  elements.on('error', (data) => {
      console.error('Payment error:', data);
  });

  • Parameter description
      1. Initialization configuration parameters (HaiPay constructor parameters)
Parameter NameRequiredTypeDescription
sandboxYesBooleanEnvironment type,default value true, optional values:
- true: Test environment (for integration testing)
- false: Production environment (for live use)
clientTokenYesStringClient Toke(clientToken)
buttonTypeNoStringButton text type, default value buy, optional values:
- plain: “Display payment logo only, no text”
- add-money: “Add funds”
- book: “Book”
- buy: “Buy” (default)
- check-out: “Checkout”
- contribute: “Donate”
- order: “Order”
- reload: “Reload”
- rent: “Rent”
- subscribe: “Subscribe”
- support: “Support”
- tip: “Tip”
- top-up: “Top-up”
buttonThemeNoStringButton theme style, default value black, optional values:
- black: Black background
- white: White background
buttonHeightNonumberButton height, default value 50
    1. Common error types and solutions
Error MessageError CauseSolution
Missing required parameters: clientTokenMissing required initialization parametersCheck if parameters clientToken are passed
Unsupported region: CNProduction environment does not support China regionCheck if there is a DOM element with the corresponding ID in the page

HaiPay.js Integration (creditCard)

HaiPay provides a convenient creditCard payment integration solution that allows you to quickly integrate payment functionality into web pages through simple configuration.
<script src="https://cashier.haipay.top/js/creditCard_1.0.0.min.js"></script>

<div>
  <div id="creditCard"></div>
</div>

  // Create instance
  const elements = creditCard.create('card', {
      sandbox: true,
      clientToken: '6cgjnxvc6kdb',
  });

  // Mount component
  elements.mount('#creditCard');

  // Card render completion callback
  elements.on('ready', (data) => {
      console.log('Card rendered successfully:', data);
  });


 // Error message
  elements.on('error', (data) => {
      console.error('Payment error:', data);
  });

  // Submit Form Information
 elements.submit()

  • Parameter description
      1. Initialization configuration parameters (HaiPay constructor parameters)
Parameter NameRequiredTypeDescription
sandboxYesBooleanEnvironment type,default value true, optional values:
- true: Test environment (for integration testing)
- false: Production environment (for live use)
clientTokenYesStringClient Toke(clientToken)
cardThemeNoStringTheme style, default value white, optional values:
- black: Black background
- white: White background
    1. Common error types and solutions
Error MessageError CauseSolution
Missing required parameters: clientTokenMissing required initialization parametersCheck if parameters clientToken are passed
Unsupported region: CNProduction environment does not support China regionCheck if there is a DOM element with the corresponding ID in the page

Transaction Limits

Transaction TypeLimit (USD)
Collection0.99-1000

Collection API

1. Collection Application

Brief Description:
  • Create a collection order
URL: USD: /usd/collect/apply Note: appId for USD, amount in USD, settlement in USD Parameters:
Parameter NameRequiredTypeDescription
appIdYesLongBusiness ID (obtained from backend, must pass corresponding business ID based on currency in URL)
orderIdYesStringMerchant order number (must be unique, length not exceeding 48)
nameYesStringUser name, recommended to use real name, format: firstName and lastName separated by space, example: Donald John Trump
phoneYesStringReal phone number (format reference Phone Number Format)
emailYesStringReal email address
amountYesStringTransaction amount (accurate to two decimal places; do not add punctuation, e.g., ”,“)
payTypeYesStringPayment method type
inBankCodeYesStringPayment method code
clientIpNoStringClient IP address
callBackUrlYesStringURL to redirect after successful payment
callBackFailUrlYesStringURL to redirect after failed payment
notifyUrlNoStringCallback URL
subjectYesStringPayment remark
bodyNoStringRemark details
partnerUserIdYesStringUnique user identifier (e.g., userId), used for risk control, must be real and valid, otherwise it will affect transactions. Format requirements: digits, uppercase and lowercase letters or common symbols -~!@#$%&*()_.
signYesStringSignature
Request Example
{
  "appId": 1054,
  "orderId": "M233323000059",
  "amount": "300",
  "phone": "09230219312",
  "email": "23423@qq.com",
  "name": "test",
  "inBankCode": "USA",
  "payType": "BANK_TRANSFER",
  "partnerUserId": "149597870",
  "sign": "af0gAHkUOyYHu9owQp8NJ4mPEeUW4vuJcjdxqLIzrVw8AvpLSjD1DXupReSG/CyuSkFRyiIvCp5u703AuGGmfgD2gKDH3Ywau41bAbG2jnHJ8mtjiSJ5iWUzanyd4Kr7d1+rETbzUl7/BkW3t0X8UUFdqpxwG8DPUjAwUKfplWDHV7koG51Ozexd80DCsmW6eWdouAZ1uNXGLYmV3ftE3BmfNRtuv1C5bfTJWrTEIOxbF6g2uYOFZTlIgrQgd7/2PsAYwQQXNz8Q8CYl4OxqCv4pXJxaLWPbR5tqZu9og5kn32C9aHW/NlU1y39vzz+4ef81yPAqUV9oHlSMSPrMmw=="
}
Response Example
{
  "status": "1",
  "error": "00000000",
  "msg": "",
  "data": {
    "orderId": "M233323000059",
    "orderNo": "6023071013539074",
    "payUrl": "",
    "clientToken": "",
    "sign": "YEoA8Y2JzQFGVzwJSqmemm1Kfv/bfyIfCqv2dp7RNzT5B72AQvdD+nt2nR4sL1HWscvmNHyVt5ovAi7MMhy3ziih/sMph+wPx4YjH3W1h5DyBvSlWvaKfKrK5ViomZ0pPYWydwRHnnRnicxToHK9S6qtSy7Q73O0hdz4hJ9p41Th3ycBl2Q9SeqSZYSY1ohcPDhdyRf2y0prb8rHgpBKzxZ5BKX/1bsE9OmsSEHAEYT8OGgko6aNe8XPAhr4G48cpWTftvnGQuzh0O65nuZRI/PF+Axt2zJCVbFHDDSREI9NlAT82ebDqhlVdxQzKE67D1nxgjb3dPmDUYHOBpmwxQ=="
  }
}
Response data parameter description
Parameter NameTypeDescription
orderIdStringMerchant order number (must be unique)
orderNoStringPlatform order number
payUrlStringPayment link
bankCodeStringPayment Method Code
clientTokenStringClient token used in JavaScript Web SDK (see HaiPaySDK.js)
signStringSignature

2. Collection Application MIT Mode

Brief Description:
  • Create MIT mode collection order
URL: USD: /usd/mit/apply Note: appId for USD, amount in USD, settlement in USD Parameters:
Parameter NameRequiredTypeDescription
appIdYesLongBusiness ID (obtained from backend, must pass corresponding business ID based on currency in URL)
orderIdYesStringMerchant order number (must be unique, length not exceeding 48)
nameNoStringUser name, recommended to use real name, format: firstName and lastName separated by space, example: Donald John Trump
phoneNoStringReal phone number (format reference Phone Number Format)
emailNoStringReal email address
amountYesStringTransaction amount (accurate to two decimal places; do not add punctuation, e.g., ”,“)
payTypeYesStringPayment method type
inBankCodeYesStringPayment method code
clientIpNoStringClient IP address
callBackUrlYesStringURL to redirect after successful payment
callBackFailUrlYesStringURL to redirect after failed payment
notifyUrlNoStringCallback URL
subjectYesStringPayment remark
bodyNoStringRemark details
partnerUserIdYesStringUnique user identifier (e.g., userId), used for risk control, must be real and valid, otherwise it will affect transactions. Format requirements: digits, uppercase and lowercase letters or common symbols -~!@#$%&*()_.
tokenIDNoStringPayment token, not required for first transaction, required for subsequent active deductions, obtained through callback
tokenNoStringApple Pay / Google Pay Token, you can obtain and transfer the data yourself or use the HaiPay page., How to get?
loadingTypeNoInteger0 (default) – Display the current/normal payment result view; 1 – Show a loading spinner with no order information.
cancelUrlNoStringIf provided, the user can click “Back” on the payment page to return to this URL after canceling the payment.
signYesStringSignature
Request Example
{
  "appId": 1054,
  "orderId": "M233323000059",
  "amount": "300",
  "phone": "09230219312",
  "email": "23423@qq.com",
  "name": "test",
  "inBankCode": "USA",
  "payType": "BANK_TRANSFER",
  "partnerUserId": "149597870",
  "sign": "af0gAHkUOyYHu9owQp8NJ4mPEeUW4vuJcjdxqLIzrVw8AvpLSjD1DXupReSG/CyuSkFRyiIvCp5u703AuGGmfgD2gKDH3Ywau41bAbG2jnHJ8mtjiSJ5iWUzanyd4Kr7d1+rETbzUl7/BkW3t0X8UUFdqpxwG8DPUjAwUKfplWDHV7koG51Ozexd80DCsmW6eWdouAZ1uNXGLYmV3ftE3BmfNRtuv1C5bfTJWrTEIOxbF6g2uYOFZTlIgrQgd7/2PsAYwQQXNz8Q8CYl4OxqCv4pXJxaLWPbR5tqZu9og5kn32C9aHW/NlU1y39vzz+4ef81yPAqUV9oHlSMSPrMmw=="
}
Response Example
{
  "status": "1",
  "error": "00000000",
  "msg": "",
  "data": {
    "orderId": "M233323000059",
    "orderNo": "6023071013539074",
    "payUrl": "",
    "clientToken": "",
    "sign": "YEoA8Y2JzQFGVzwJSqmemm1Kfv/bfyIfCqv2dp7RNzT5B72AQvdD+nt2nR4sL1HWscvmNHyVt5ovAi7MMhy3ziih/sMph+wPx4YjH3W1h5DyBvSlWvaKfKrK5ViomZ0pPYWydwRHnnRnicxToHK9S6qtSy7Q73O0hdz4hJ9p41Th3ycBl2Q9SeqSZYSY1ohcPDhdyRf2y0prb8rHgpBKzxZ5BKX/1bsE9OmsSEHAEYT8OGgko6aNe8XPAhr4G48cpWTftvnGQuzh0O65nuZRI/PF+Axt2zJCVbFHDDSREI9NlAT82ebDqhlVdxQzKE67D1nxgjb3dPmDUYHOBpmwxQ=="
  }
}
Response data parameter description
Parameter NameTypeDescription
orderIdStringMerchant order number (must be unique)
orderNoStringPlatform order number
payUrlStringPayment link
clientTokenStringClient token used in JavaScript Web SDK (see HaiPaySDK.js)
signStringSignature

3. Collection Query

Brief Description:
  • Query collection order
URL: USD: /usd/collect/query Parameters:
Parameter NameRequiredTypeDescription
appIdYesLongBusiness ID (obtained from backend, must pass corresponding business ID based on currency in URL)
orderIdYesStringMerchant order number
orderNoNoStringPlatform order number (faster response)
signYesStringSignature
Request Example
{
  "appId": 1054,
  "orderId": "M22222000028",
  "sign": "EmyJGm3ELzG4FsOd0Krs9ncbSjo4oTGuXWML+7djYla3+VAwd9wS17z38p/7U2ZAjroO04XrE7YXcB1o76Dtyipj3h3bJzs7FYma1QNkMUdt9hh7m8U6hMsMQX7vIWHtXNwz4pbTSC75+kQWXaCew7KoE6LXECdJU8AISgNgeki2TK9R0pCfshr0Z2SZBPeuT6OvIH5LdmqgdZhuqnffGU2qnXk4KMkO848e6/WALLBR+LE1wyKHfPnYVcuKSMVYxkvKyyIL5JIPEgW0o5bh4RCbaUn3NZtyYwrU1uQ3ZDFRThm9j6XAQP+LBlmq3nOePqBtp/VDVarRaV+7FbQg3A=="
}
Response Example
{
  "status": "1",
  "error": "00000000",
  "msg": "",
  "data": {
    "orderId": "M22222000028",
    "orderNo": "6023042811314347",
    "amount": "50.00",
    "actualAmount": "0.00",
    "fee": "0.00",
    "status": 1,
    "sign": "fP433ygWVDLVGxYkVnIJj7riGq0U3vyVX+MbBAImxfGLZkZcEAHVEoVYuULZSmXAAXKRSyd67WlDNm+24pougM54ofAoH4HMtCL2tfCoBReFyz3z02AGKkrKE2xWhSpWoqfQoBvzwuN5iGMMu0s9Q1YvqiwJ8WDVIENnmiIyD8qDJN7caHTW2US14/faG+69AvnuIgJ/nu7/jogOlgEYdZdVYU7gcRDE+d47KjlFGswQkJ/h/uzV7cWtUqrtOO7ZnZ3/z33Xx8awokX36QoYcPSWAU0h+Ij9O9402HNhm1eTbYcLU0uI/z8xCAtyAI/tTyiFijpiNlxUKQj+zKsILw=="
  }
}
Response data parameter description
Parameter NameTypeDescription
orderIdStringMerchant order number (must be unique)
orderNoStringPlatform order number
amountStringTransaction amount
actualAmountStringAmount received
feeStringHandling fee
statusIntegerStatus (0 - Not started, 1 - In progress, 2 - Success (final), 3 - Failure (final), -1 - Pending confirmation)
payTimeStringPayment success time (present when status=2) (local time), format: yyyy-MM-dd HH:mm:ss
errorMsgStringPayment failure reason (present when status=3)
signStringSignature

4. Refund Application

Brief Description:
  • Initiate a refund operation for the original credit card transaction order. Please pay attention to the status values returned synchronously. It is recommended to use the query interface for status checks.
URL: USD: /usd/refund/apply Parameters:
Parameter NameRequiredTypeDescription
appIdYesLongBusiness ID (obtained from backend, must pass corresponding business ID based on currency in URL)
orderIdYesStringMerchant refund application order number (new merchant order number, cannot use original collection merchant order number)
orderNoYesStringPlatform order number (original collection platform order number returned)
signYesStringSignature
Response data parameter description
Parameter NameTypeDescription
appIdStringBusiness ID
orderNoStringPlatform order number (original collection platform order number returned)
orderIdStringMerchant refund application order number
refundNoStringPlatform refund number for this refund
statusStringRefund status: 1 indicates refund application success, 0 indicates processing, 2 indicates failure. Initially returns processing, status needs to be checked via query interface later
errorMsgStringError message (may not always have a value)
signStringSignature

5. Refund Query

Brief Description:
  • Query the result of the refunded order.
URL: USD: /usd/refund/refundQuery Parameters:
Parameter NameRequiredTypeDescription
appIdYesLongBusiness ID (obtained from backend, must pass corresponding business ID based on currency in URL)
orderIdNoStringMerchant refund application order number
refundNoNoStringPlatform refund number (platform order number returned when refund was applied, if provided, prioritize checking this field)
signYesStringSignature
Response data parameter description
Parameter NameTypeDescription
appIdStringMerchant order number (must be unique)
orderNoStringPlatform order number (original collection platform order number)
orderIdStringMerchant application order number
refundNoStringPlatform refund number
statusStringRefund status: 1 indicates refund application success, 0 indicates processing, 2 indicates failure. Refund result is based on this status
errorMsgStringError message (may not always have a value)
signStringSignature

6. Payment Methods

CurrencyPayment Type (payType)Payment Code (inBankCode)LimitsStatusDescription
USDBANK_TRANSFERCREDIT_CARD0.99-1000AvailableVISA
USDBANK_TRANSFERCREDIT_CARD0.99-1000AvailableMasterCard
USDBANK_TRANSFERCREDIT_CARD0.99-1000AvailableJCB
USDEWALLETGOOGLE_PAY0.99-1000AvailableGoogle Pay
USDEWALLETAPPLE_PAY0.99-1000AvailableApple Pay

7. Test Card Numbers

For use in test environment only

Simulate Successful Payment

Use the following test card numbers, enter any CVC (3-digit number) and expiration date (future date) to simulate successful payment:
  • Card Number 1: 4242424242424242

Simulate Payment Failure

Use the following test card numbers with invalid data to simulate payment failure:
  • Card Number 1: 4000000000009995
  • Invalid month: 13
  • Invalid CVV: 99

8. MIT (Merchant Initiated Transaction) Mode Description

MIT (Merchant Initiated Transaction) Refers to transactions that merchants can initiate without the user being present after the user completes a one-time payment authorization. This mode is widely used in business scenarios such as subscription payments, installment payments, membership renewals, delayed deductions, etc.

Basic Process

  1. User Authorization
    • User enters payment information during the first payment and completes necessary identity verification.
    • Merchant saves the user’s payment credentials for subsequent deduction requests.
  2. Merchant-Initiated Deduction
    • Merchant directly uses saved payment credentials to initiate deduction requests based on agreed cycles or conditions.
    • Since the transaction is an offline scenario (off-session), meaning the user is not involved in the transaction, the system will complete processing based on user authorization and compliance requirements.
  3. Authentication Requirements
    • In most cases, transactions will complete directly.
    • If the issuing bank or risk control system requires re-verification, the transaction may enter a pending user confirmation state, requiring user supplementary verification to complete.

Mode Features

  • Enhanced Experience: Users don’t need to manually enter payment information each time.
  • Compliant and Secure: Meets international payment regulations and Strong Customer Authentication (SCA) requirements.
  • Wide Application: Suitable for subscription billing, auto-renewal, installment deductions, delayed settlement, etc.

MIT Flow Diagram

9. Apple Pay / Google Pay Token Acquisition Method Description

Integration Process

  • No need to apply for an Apple Pay or Google Pay developer account — HaiPay handles it for you.
  • Include the JavaScript script ([https://js.stripe.com/v3/])
  • Page structure requirements:
    • Payment button container: used for rendering the Apple Pay / Google Pay button.
  • Quick integration example
<script src="https://js.stripe.com/v3"></script>

<div id="appId">
  <div id="applePay-googlePay"></div>
</div>

      initApplePayGooglePay() {
            const stripe = Stripe('A key is required — please contact HaiPay to obtain it.'); //This key is not shared between production and testing environments.
            const paymentRequest = stripe.paymentRequest({
            country: "HK",
            currency: "usd",
            total: {
                label: "Haipay",
                amount: 0.99 * 100, // The unit is cents.
            },
            requestPayerName: true,
            requestPayerEmail: true,
            });

            // Use `paymentRequestButton` to create an Apple Pay / Google Pay button.
            const elements = stripe.elements();
            const prButton = elements.create("paymentRequestButton", {
               paymentRequest: paymentRequest,
            });

            // Check whether the browser supports Apple Pay or Google Pay.
            paymentRequest.canMakePayment().then((result) => {
                if (result && (result.applePay || result.googlePay)) {
                    prButton.mount("#applePay-googlePay");
                } else {
                    document.getElementById("applePay-googlePay").style.display = "none";
                    document.getElementById("applePay-googlePay-not-supported").style.display = 'block';
                }
            });

            paymentRequest.on("paymentmethod", async (ev) => {
                //`ev.paymentMethod.id` is the required token, which should be passed as a parameter when calling the `/usd/mit/apply` API.
            });
          }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"/>
    <meta name="description" content="You have a payment link that needs to be paid. Please click the link below to make the payment." />
    <title>Google Pay and Apple Pay Demo</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/8.0.20/jsrsasign-all-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.15.14/theme-chalk/index.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.15.14/index.js"></script>
    <script src="https://js.stripe.com/v3/"></script>


    <style type="text/tailwindcss">
        @layer utilities {
            .apple-pay-button {
                background-color: black;
                color: white;
                border-radius: 9999px;
                padding: 12px 24px;
                font-size: 17px;
                font-weight: 500;
                cursor: pointer;
                transition: background-color 0.2s;
                display: inline-flex;
                align-items: center;
                justify-content: center;
            }
            .apple-pay-button:hover {
                background-color: #333;
            }
            .apple-pay-button img {
                margin-right: 8px;
                height: 20px;
            }
        }
      .content {
        width: 100%;
        max-width: 600px;
        background: #fff;
        box-sizing: border-box;
        box-shadow: 0 0 calc(8.53333vmin / 32 * 8) #ccc;
        padding:calc(8.53333vmin / 32 * 20) calc(8.53333vmin / 32 * 10) calc(8.53333vmin / 32 * 10);
        margin: 0 auto 20px;
        border-radius: calc(8.53333vmin / 32 * 6);
      }
    </style>
</head>
<body class="bg-gray-50 font-sans">
    <div id="app">
        <div class="container mx-auto px-4 py-12 max-w-4xl">
            <header class="mb-10 text-center">
                <h1 class="text-3xl font-bold text-gray-900 mb-2">Google Pay And Apple Pay Demo</h1>
                <p class="text-gray-600">Experience a safe and fast payment method.</p>
            </header>

         <div class="content">
            <el-form ref="form" :rules="rules" :model="form">
                <el-form-item label="appId" prop="appId">
                  <el-input v-model="form.appId" placeholder="Please enter the appId." />
                </el-form-item>
                <el-form-item label="amount" prop="amount">
                  <el-input v-model="form.amount" placeholder="Please enter the amount." />
                </el-form-item>
                <el-form-item label="phone" prop="phone">
                  <el-input v-model="form.phone" placeholder="Please enter the phone." />
                </el-form-item>
                <el-form-item label="email" prop="email">
                  <el-input v-model="form.email" placeholder="Please enter the email." />
                </el-form-item>
                <el-form-item label="key" prop="key">
                  <el-input v-model="form.key" placeholder="Please enter the key." />
                </el-form-item>
                <el-form-item label="privateKey" prop="privateKey">
                  <el-input v-model="form.privateKey" placeholder="Please enter the privateKey."  type="textarea" resize="none" :autosize="{ minRows: 4, maxRows: 10 }"  />
                </el-form-item>
            </el-form>
            </div>


            <div class="text-center">

                <div id="applePay-googlePay"></div>

                <div id="applePay-googlePay-not-supported" class="text-gray-500 mb-6 hidden">
                    <p><i class="fa fa-info-circle mr-2"></i>This device does not support Google Pay or Apple Pay.</p>
                </div>

            </div>
        </div>
    </div>

  <script>
      new Vue({
        el: "#app",
        data() {
          return {
             form: {
                token: '',
                appId: ,
                orderId: Date.now(),
                amount: "0.99",
                phone: "18801234567",
                email: "test@haipay.tech",
                name: "Haipay",
                inBankCode: "APPLE_PAY",
                payType: "EWALLET",
                partnerUserId: Date.now(),
                key: '',
                privateKey: ''
            },
            rules: {
              appId: [
                { required: true, trigger: 'blur' }
              ],
              amount: [
                { required: true, trigger: 'blur' }
              ],
              phone: [
                { required: true, trigger: 'blur' }
              ],
              email: [
                { required: true, trigger: 'blur' }
              ],
              name: [
                { required: true, trigger: 'blur' }
              ],
              key: [
                { required: true, trigger: 'blur' }
              ],
              privateKey: [
                { required: true, trigger: 'blur' }
              ],
            },
            baseURL: 'https://uat-interface.haipay.asia',
            isH5: true,
            applePayButton: null,
          };
        },
        computed: {},
        created() {
          this.isMobileDevice()
          this.applePayButton = document.getElementById('applePay-googlePay');
          this.initApplePay()
        },
        methods: {
          isMobileDevice() {
            let self = this
            if(typeof window.orientation !== 'undefined'){
              self.isH5 = true
            } else {
              self.isH5 = false
            }
          },
          initApplePay() {
            const self = this
            const stripe = Stripe('A key is required — please contact HaiPay to obtain it.'); //This key is not shared between production and testing environments.
            const paymentRequest = stripe.paymentRequest({
            country: "HK",
            currency: "usd",
            total: {
                label: "Haipay",
                amount: Number(self.form.amount) * 100, // The unit is cents.
            },
            requestPayerName: true,
            requestPayerEmail: true,
            });

            // Use `paymentRequestButton` to create an Apple Pay / Google Pay button.
            const elements = stripe.elements();
            const prButton = elements.create("paymentRequestButton", {
               paymentRequest: paymentRequest,
            });

            // Check whether the browser supports Apple Pay or Google Pay.
            paymentRequest.canMakePayment().then((result) => {
                if (result && (result.applePay || result.googlePay)) {
                    prButton.mount("#applePay-googlePay");
                } else {
                    document.getElementById("applePay-googlePay").style.display = "none";
                    document.getElementById("applePay-googlePay-not-supported").style.display = 'block';
                }
            });

            paymentRequest.on("paymentmethod", async (ev) => {
                if(ev.walletName === 'googlePay') {
                  self.form.inBankCode = 'GOOGLE_PAY'
                } else if(ev.walletName === 'applePay') {
                  self.form.inBankCode = 'APPLE_PAY'
                }
                self.form.token = ev.paymentMethod.id //`ev.paymentMethod.id` is the required token, which should be passed as a parameter when calling the `/usd/mit/apply` API.
                const requestData = {
                    headers: { 'content-type': 'application/json' },
                    body: self.form
                };
                    const signedBody = self.generateSign(requestData);
                    const response = await fetch(`${self.baseURL}/usd/mit/apply`,
                        {
                            method: 'POST',
                            headers: {
                            'Content-Type': 'application/json',
                            },
                            body: signedBody
                        });
                    const res = await response.json()
                    if(res.status === '1') {
                        self.orderNo = res.data.orderNo
                        if(self.isH5) {
                            window.location.href = res.data.payUrl
                        }else {
                            window.open(res.data.payUrl, "_blank");
                        }
                    }

                ev.complete("success");
            });
          },
         generateSign(requestData) {
            let param = {};
            if (requestData.body) {
                const contentType = requestData.headers['content-type'] || '';
                if (contentType.toLowerCase().includes('application/json')) {
                    try {
                        const jsonData = typeof requestData.body === 'string'
                            ? JSON.parse(requestData.body)
                            : requestData.body;

                        for (let key in jsonData) {
                            if (jsonData[key] !== '') {
                                param[key] = jsonData[key];
                            }
                        }
                    } catch (e) {
                        console.log('The request body is not in JSON format.');
                    }
                }
            }

            const sortedKeys = Object.keys(param)
                .filter(key => !['privateKey', 'sign', 'key'].includes(key))
                .sort();
            const paramString = sortedKeys.map(key => `${key}=${param[key]}`).join('&');

            let body = typeof requestData.body === 'string'
                ? requestData.body
                : JSON.stringify(requestData.body);
            let jsonData = JSON.parse(body);
            let key = jsonData.key;

            const stringSignTemp = `${paramString}&key=${key}`;
            console.log('signstring:', stringSignTemp);

            let privateKey = `
        -----BEGIN PRIVATE KEY-----
        ${jsonData.privateKey}
        -----END PRIVATE KEY-----
            `.trim();

            // sign
            const sig = new KJUR.crypto.Signature({ alg: 'SHA256withRSA' });
            sig.init(privateKey);
            sig.updateString(stringSignTemp);
            const signatureHex = sig.sign();
            const sign = hextob64(signatureHex);

            // add sign to request body
            jsonData.sign = sign;
            return JSON.stringify(jsonData);
         },
        },
      });
    </script>
</body>
</html>

Last modified on April 17, 2026