Skip to main content
One-time payments are single, non-recurring transactions where customers pay once for a product or service. The customer selects a HitPay payment method, completes the payment via QR code or redirect, and the transaction is recorded in Stripe.

How It Works

This integration connects Stripe’s Payment Element with HitPay’s Payment Request API, allowing customers to pay using local payment methods while keeping all transaction records in Stripe.

Key Concepts

API References

HitPay Payment Request API

Create payment requests and generate QR codes for local payment methods.

HitPay Embedded QR Payments

Embed QR codes directly in your checkout for seamless mobile payments.

Payment Flow

Step 1: Configure Custom Payment Methods

Register each HitPay payment method as a Custom Payment Method (CPM) type in your Stripe Dashboard, map those CPM Type IDs to their HitPay method identifiers in a config file, and load them into the Stripe Elements provider so they appear as options in your checkout.
1

Create Custom Payment Methods on Stripe Dashboard

Stripe DashboardCreate Custom Payment Method types in your Stripe Dashboard for each HitPay payment method you want to offer.After creating the custom payment method, the Dashboard displays the custom payment method ID (beginning with cpmt_) that you need for the next step.

Create CPM in Stripe Dashboard

Follow Stripe’s guide to create Custom Payment Method types and get your CPM Type IDs.

Download Payment Icons

Download official HitPay payment method icons (PayNow, ShopeePay, GrabPay, FPX, and more) optimized for Stripe Custom Payment Methods.
2

Create Configuration File

Server-sideThis configuration file maps the Custom Payment Methods you created in the Stripe Dashboard to their corresponding HitPay payment method identifiers. Each entry links a Stripe CPM Type ID (e.g. cpmt_xxx) to the HitPay API method name used when creating a payment request.See the HitPay Payment Methods Reference for the full list of supported payment method names and their identifiers.The chargeAutomatically flag indicates whether a payment method supports tokenized or recurring payments — these methods can be used to charge customers automatically without requiring re-authorization each time.The code below is a sample — adapt it to the payment methods you’ve configured:
You’ll have different CPM Type IDs in sandbox and production — they are separate Stripe accounts. Consider using environment variables or an ids: { sandbox: string, production: string } structure so you can switch between environments without code changes.
3

Add Custom Payment Method Type to Stripe Elements Configuration

Client-sideNext, add the custom payment method type to your Stripe Elements configuration. In your checkout.js file where you initialise Stripe Elements, specify the customPaymentMethods to add to the Payment Element. Provide the custom payment method ID from the previous step, the options.type and an optional subtitle.Load Stripe.js with the beta flag:
After loading, the Payment Element shows your custom payment method.

Add CPM to Elements

Learn more about configuring Custom Payment Methods in the Payment Element.

Step 2: Display Payment on Stripe Payment Elements

When a customer selects a HitPay payment method in the Payment Element, your backend creates a HitPay payment request and returns a QR code or deep link for the customer to complete payment on their mobile device.
1

Configure Environment Variables

Server-sideSet up the required API keys and configuration for both Stripe and HitPay. These credentials authenticate your server with both payment platforms.
Never expose STRIPE_SECRET_KEY or HITPAY_API_KEY to the client.
2

Create HitPay Payment Request

Server-sideWhen a user selects a CPM in the Payment Element, create a HitPay payment request and display the QR code:
Displaying QR Codes: The generate_qr: true parameter returns QR code data in qr_code_data.qr_code. For detailed guidance on rendering QR codes and handling different payment methods, see our Embedded QR Code Payments guide.
App-based methods (ShopeePay, GrabPay): Some payment methods don’t generate a QR code — instead, HitPay returns a direct_link.direct_link_url that opens the payment app directly. When directLinkUrl is present, redirect the customer to that URL instead of displaying a QR code.

Embedded QR Code Payments

Learn how to embed and display QR codes for PayNow, ShopeePay, and other supported payment methods.
3

Display QR Code in Payment Element

Client-sideRender the QR code in your checkout form when a customer selects a HitPay payment method. The customer scans the QR code with their mobile app to complete the payment.

Step 3: Record Payment Confirmation

Once the customer pays via HitPay, your backend receives a webhook, verifies the payment, and records it in Stripe using the Payment Records API — making it visible in your Stripe Dashboard alongside native card payments.
Without this step, HitPay payments only appear in your HitPay Dashboard. By recording them via Stripe’s Payment Records API, you get a single source of truth for all transactions — cards, PayNow, ShopeePay, and more — all in one place.

Stripe Payment Records API

Learn how Payment Records work and how they appear in your Stripe Dashboard.
1

Listen for Payment Confirmation

Server-side
2

Record the Payment to Your Stripe Account

Server-sideOnce HitPay confirms the payment is complete, call stripe.paymentRecords.reportPayment() to create a Payment Record (prec_xxx) in Stripe. This is what makes the transaction visible in your Stripe Dashboard alongside native card payments.
The original PaymentIntent remains "Incomplete" — this is expected for external payments. The Payment Record is the canonical record of the transaction and what Stripe uses for revenue reporting.
Each field in the payload serves a specific purpose:

Testing

Sandbox Testing

  1. Set NEXT_PUBLIC_HITPAY_ENV=sandbox in your environment
  2. Use HitPay sandbox API credentials
  3. When a QR code is displayed, HitPay provides a “Complete Mock Payment” link
  4. Click this link to simulate a successful payment

Production Testing

  1. Switch to production credentials
  2. Use real payment apps to scan QR codes
  3. Verify payments appear in both HitPay and Stripe dashboards
PaymentIntents will show as “Incomplete” in Stripe - this is expected. External payments are tracked via Payment Records (prec_* IDs).

FAQ

  • Verify the CPM Type is enabled in Stripe Dashboard
  • Check that the CPM ID in your config matches the Dashboard
  • Ensure you’re loading Stripe.js with custom_payment_methods_beta_1
  • Not all HitPay methods support QR codes (e.g., GrabPay uses redirect)
  • Check the checkoutUrl fallback is being displayed
  • Verify the payment method is enabled in HitPay Dashboard
  • The payment method may not be enabled in your HitPay account
  • Some methods aren’t available in sandbox mode
  • Check the error message for specific details
  • Check server logs for Payment Records API errors
  • Verify your Stripe API version includes the beta flag
  • The payment still succeeded if HitPay shows completed
Last modified on March 30, 2026