Implement out-of-band subscriptions with Stripe Custom Payment Methods and HitPay
Out-of-band subscriptions allow customers to pay each invoice manually using any HitPay payment method. This is the same flow as one-time payments, repeated per billing cycle. This approach works with all payment methods including QR-based ones like PayNow that cannot be tokenized.
This integration connects Stripe’s Subscription API with HitPay’s Payment Request API, allowing customers to pay each invoice using local payment methods while keeping all subscription records in Stripe.
Create payment requests with QR codes for one-time payments.
Stripe Subscriptions API
Manage subscription lifecycle and invoice generation.
Out-of-band subscriptions work with all payment methods since each invoice is paid as a one-time payment. This is ideal for QR-based methods like PayNow that cannot be tokenized.
Stripe DashboardCreate Custom Payment Method types in your Stripe Dashboard for each HitPay payment method you want to offer.
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-sideMap your Stripe CPM Type IDs to HitPay payment methods. For out-of-band subscriptions, you only need the hitpayMethod (one-time payment method).
Server-sideSet up the required API keys and configuration for both Stripe and HitPay.
Copy
Ask AI
# Stripe (Standard Account Keys)NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxSTRIPE_SECRET_KEY=sk_test_xxx# HitPayHITPAY_API_KEY=xxxHITPAY_SALT=xxxNEXT_PUBLIC_HITPAY_ENV=sandbox # or 'production'
Never expose your STRIPE_SECRET_KEY or HITPAY_API_KEY to the client. These should only be used server-side.
2
Create Subscription with Send Invoice
Server-sideCreate a Stripe subscription with send_invoice collection method. This creates invoices that customers pay manually each billing cycle.
Copy
Ask AI
// app/api/create-subscription/route.tsimport { NextResponse } from 'next/server';import { stripe } from '@/lib/stripe';export async function POST(request: Request) { const { priceId, email } = await request.json(); // Create or retrieve customer let customer; const existingCustomers = await stripe.customers.list({ email, limit: 1 }); if (existingCustomers.data.length > 0) { customer = existingCustomers.data[0]; } else { customer = await stripe.customers.create({ email }); } // Create subscription with manual invoice payment const subscription = await stripe.subscriptions.create({ customer: customer.id, items: [{ price: priceId }], collection_method: 'send_invoice', days_until_due: 0, // Invoice due immediately payment_settings: { payment_method_types: ['card'], }, }); // Finalize invoice to get PaymentIntent const invoice = await stripe.invoices.retrieve(subscription.latest_invoice as string); const finalizedInvoice = await stripe.invoices.finalizeInvoice(invoice.id); // Get client secret for Payment Element let clientSecret: string; if (finalizedInvoice.payment_intent) { const pi = await stripe.paymentIntents.retrieve( finalizedInvoice.payment_intent as string ); clientSecret = pi.client_secret!; } else { // Create a UI PaymentIntent if needed const pi = await stripe.paymentIntents.create({ amount: finalizedInvoice.amount_due, currency: finalizedInvoice.currency, customer: customer.id, metadata: { invoice_id: finalizedInvoice.id }, }); clientSecret = pi.client_secret!; } return NextResponse.json({ subscriptionId: subscription.id, invoiceId: finalizedInvoice.id, clientSecret, customerId: customer.id, billingType: 'out_of_band', type: 'payment', });}
The key difference from auto-charge is collection_method: 'send_invoice' with days_until_due: 0, which creates an invoice due immediately that customers pay manually.
Server-sideUse the same HitPay Payment Request endpoint from the one-time payments flow. When a customer selects a custom payment method, create a payment request for the invoice amount.
HitPay Payment Request
See the one-time payments guide for the HitPay payment request implementation.
2
Display QR Code and Poll for Payment
Client-sideShow the QR code or redirect URL and poll for payment completion. This is the same flow as one-time payments.
InfoEach billing cycle, Stripe automatically generates a new invoice. Since out-of-band subscriptions don’t use tokenized payment methods, customers pay each invoice manually using the same one-time payment flow.How it works:
Stripe generates a new invoice at the start of each billing cycle
You notify the customer (via email or your app) that a new invoice is ready
Customer returns to your payment page and pays the invoice using any HitPay payment method
The payment is recorded and the invoice is marked as paid
Unlike auto-charge subscriptions, there’s no webhook to automatically charge the customer. You can optionally set up a webhook for invoice.created to send payment reminders.