@qazuor/qzpay-stripe
@qazuor/qzpay-stripe
Provider View on npm @qazuor/qzpay-stripe
Full Stripe integration for QZPay.
Installation
pnpm add @qazuor/qzpay-stripe stripeSetup
import { createQZPayStripeAdapter } from '@qazuor/qzpay-stripe';
const stripeAdapter = createQZPayStripeAdapter({ secretKey: process.env.STRIPE_SECRET_KEY!, webhookSecret: process.env.STRIPE_WEBHOOK_SECRET});
// Or use the class directlyimport { QZPayStripeAdapter } from '@qazuor/qzpay-stripe';
const stripeAdapter = new QZPayStripeAdapter({ secretKey: process.env.STRIPE_SECRET_KEY!});Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
secretKey | string | Yes | Stripe secret key |
webhookSecret | string | No | Webhook signing secret |
Using with QZPay
import { createQZPayBilling } from '@qazuor/qzpay-core';import { createQZPayStripeAdapter } from '@qazuor/qzpay-stripe';import { createQZPayDrizzleAdapter } from '@qazuor/qzpay-drizzle';
const billing = createQZPayBilling({ storage: createQZPayDrizzleAdapter(db), paymentAdapter: createQZPayStripeAdapter({ secretKey: process.env.STRIPE_SECRET_KEY! })});Sub-Adapters
The Stripe adapter provides access to specialized sub-adapters:
stripeAdapter.customers // QZPayStripeCustomerAdapterstripeAdapter.subscriptions // QZPayStripeSubscriptionAdapterstripeAdapter.payments // QZPayStripePaymentAdapterstripeAdapter.checkout // QZPayStripeCheckoutAdapterstripeAdapter.prices // QZPayStripePriceAdapterstripeAdapter.webhooks // QZPayStripeWebhookAdapterstripeAdapter.setupIntents // QZPayStripeSetupIntentAdapterstripeAdapter.vendors // QZPayStripeVendorAdapter (if Connect configured)Customer Adapter
// Create customer in Stripeconst stripeCustomerId = await stripeAdapter.customers.create({ email: 'user@example.com', name: 'John Doe', metadata: { userId: '123' }});
// Update customerawait stripeAdapter.customers.update(stripeCustomerId, { name: 'Jane Doe'});
// Delete customerawait stripeAdapter.customers.delete(stripeCustomerId);
// Retrieve customer detailsconst customer = await stripeAdapter.customers.retrieve(stripeCustomerId);Subscription Adapter
// Create subscriptionconst subscription = await stripeAdapter.subscriptions.create( stripeCustomerId, { trialPeriodDays: 14 }, 'price_xxx');
// Update subscriptionawait stripeAdapter.subscriptions.update(stripeSubscriptionId, { metadata: { tier: 'pro' }});
// Cancel subscriptionawait stripeAdapter.subscriptions.cancel(stripeSubscriptionId, true); // atPeriodEnd
// Pause subscription (uses pause_collection)await stripeAdapter.subscriptions.pause(stripeSubscriptionId);
// Resume subscriptionawait stripeAdapter.subscriptions.resume(stripeSubscriptionId);Payment Adapter
// Create payment intentconst payment = await stripeAdapter.payments.create(stripeCustomerId, { amount: 9900, currency: 'usd', paymentMethodId: 'pm_xxx'});
// Capture authorized paymentawait stripeAdapter.payments.capture(paymentIntentId);
// Cancel paymentawait stripeAdapter.payments.cancel(paymentIntentId);
// Refund paymentconst refund = await stripeAdapter.payments.refund({ amount: 5000, reason: 'requested_by_customer'}, paymentIntentId);Checkout Adapter
// Create checkout sessionconst session = await stripeAdapter.checkout.create({ mode: 'subscription', customerId: stripeCustomerId, successUrl: 'https://example.com/success', cancelUrl: 'https://example.com/cancel'}, ['price_xxx']);
// Retrieve sessionconst session = await stripeAdapter.checkout.retrieve(sessionId);
// Expire sessionawait stripeAdapter.checkout.expire(sessionId);Setup Intent Adapter
// Create setup intent for saving payment methodsconst setupIntent = await stripeAdapter.setupIntents.create({ customerId: stripeCustomerId, usage: 'off_session'});
// Confirm setup intentawait stripeAdapter.setupIntents.confirm({ setupIntentId: setupIntent.id, paymentMethodId: 'pm_xxx'});
// Cancel setup intentawait stripeAdapter.setupIntents.cancel(setupIntentId);Price Adapter
// Create a productconst productId = await stripeAdapter.prices.createProduct( 'Pro Plan', 'Monthly subscription to Pro features');
// Create a priceconst priceId = await stripeAdapter.prices.create({ amount: 2900, currency: 'usd', interval: 'month', intervalCount: 1}, productId);
// Archive a priceawait stripeAdapter.prices.archive(priceId);Webhook Handling
import { mapStripeEventToQZPayEvent, extractStripeEventData} from '@qazuor/qzpay-stripe';
// Construct and verify webhook eventconst event = stripeAdapter.webhooks.constructEvent( rawBody, signature);
// Verify signature onlyconst isValid = stripeAdapter.webhooks.verifySignature(rawBody, signature);
// Map Stripe event to QZPay event typeconst qzpayEventType = mapStripeEventToQZPayEvent(event.type);
// Extract relevant data from eventconst data = extractStripeEventData(event);// Returns: { entityType, entityId, customerId?, subscriptionId?, invoiceId? }3D Secure / SCA Support
import { isPaymentRequires3DS, extract3DSDetails} from '@qazuor/qzpay-stripe';
// Check if payment requires 3DSif (isPaymentRequires3DS(event)) { const details = extract3DSDetails(event); // details.status: 'required' | 'succeeded' | 'failed' | etc. // details.nextActionUrl: URL for 3DS challenge // details.clientSecret: For client-side confirmation}Dispute Handling
import { isDisputeEvent, extractDisputeDetails} from '@qazuor/qzpay-stripe';
if (isDisputeEvent(event)) { const dispute = extractDisputeDetails(event); // Handle dispute}Pending Update Handling
import { isPendingUpdateEvent, extractPendingUpdateDetails} from '@qazuor/qzpay-stripe';
if (isPendingUpdateEvent(event)) { const pendingUpdate = extractPendingUpdateDetails(event); // Handle pending subscription update}Fraud Warning Handling
import { isFraudWarningEvent, extractFraudWarningDetails} from '@qazuor/qzpay-stripe';
if (isFraudWarningEvent(event)) { const fraudWarning = extractFraudWarningDetails(event); // Handle fraud warning}Event Classification
import { classifyStripeEvent, requiresImmediateAction} from '@qazuor/qzpay-stripe';
// Classify event by categoryconst category = classifyStripeEvent(event);// Returns: 'customer' | 'subscription' | 'payment' | 'invoice' | 'dispute' | etc.
// Check if event requires immediate actionif (requiresImmediateAction(event)) { // Handle high-priority event immediately}Stripe Connect (Marketplace)
import { QZPayStripeAdapter } from '@qazuor/qzpay-stripe';
const stripeAdapter = new QZPayStripeAdapter( { secretKey: process.env.STRIPE_SECRET_KEY! }, { // Connect config platformAccountId: 'acct_xxx' });
// Create connected accountconst accountId = await stripeAdapter.vendors.createAccount({ email: 'vendor@example.com', name: 'Vendor Store'});
// Create onboarding linkconst onboardingUrl = await stripeAdapter.vendors.createAccountLink( accountId, 'https://example.com/refresh', 'https://example.com/return', 'account_onboarding');
// Create payout to connected accountconst payoutId = await stripeAdapter.vendors.createPayout( accountId, 10000, // amount in cents 'usd');
// Create transfer to connected accountconst transferId = await stripeAdapter.vendors.createTransfer( accountId, 5000, 'usd', paymentIntentId);Event Mapping
| Stripe Event | QZPay Event |
|---|---|
customer.created | customer.created |
customer.updated | customer.updated |
customer.deleted | customer.deleted |
customer.subscription.created | subscription.created |
customer.subscription.updated | subscription.updated |
customer.subscription.deleted | subscription.canceled |
customer.subscription.paused | subscription.paused |
customer.subscription.resumed | subscription.resumed |
customer.subscription.trial_will_end | subscription.trial_ending |
invoice.created | invoice.created |
invoice.paid | invoice.paid |
invoice.payment_failed | invoice.payment_failed |
invoice.voided | invoice.voided |
payment_intent.succeeded | payment.succeeded |
payment_intent.payment_failed | payment.failed |
charge.refunded | payment.refunded |
charge.dispute.created | payment.disputed |
checkout.session.completed | checkout.completed |
checkout.session.expired | checkout.expired |
Testing
Use Stripe test mode keys for development:
STRIPE_SECRET_KEY=sk_test_xxxSTRIPE_WEBHOOK_SECRET=whsec_xxxTest Card Numbers
| Card | Behavior |
|---|---|
4242424242424242 | Successful payment |
4000000000000002 | Card declined |
4000002500003155 | Requires 3D Secure |
4000000000009995 | Insufficient funds |
4000000000000069 | Expired card |
Testing Webhooks
# Install Stripe CLIstripe listen --forward-to localhost:3000/webhooks/stripe
# Trigger test eventsstripe trigger payment_intent.succeededstripe trigger customer.subscription.createdAccessing Stripe Client
For advanced use cases, access the underlying Stripe client:
const stripe = stripeAdapter.getStripeClient();
// Use native Stripe SDK methodsconst products = await stripe.products.list({ limit: 10 });