Payments Require Precision

Payment integration is one of the most critical parts of any SaaS application. Errors in payment processing cause revenue loss, customer frustration, and potential legal liability. At Nexis Limited, we have integrated Stripe across multiple SaaS products — Bondorix, Ultimate HRM, Digital Menu, and Digital School — with subscription billing, usage-based pricing, and one-time payments.

PCI Compliance Basics

The Payment Card Industry Data Security Standard (PCI DSS) governs how cardholder data is handled. The simplest way to achieve compliance is to never touch card data:

  • Use Stripe Elements or Stripe Checkout to collect card information directly from the user's browser to Stripe's servers. Card numbers never touch your server.
  • Store only Stripe customer IDs and payment method IDs in your database — never card numbers, CVVs, or expiration dates.
  • Use tokenization — Stripe converts card details into tokens that can only be used by your Stripe account.

Stripe Integration Architecture

Checkout Flow

Stripe Checkout is a hosted payment page managed by Stripe. Redirect users to Checkout for payment collection and receive a webhook when payment completes. Simplest integration — Stripe handles the entire UI, validation, 3D Secure authentication, and receipts.

Payment Intents

For custom payment UIs, use the Payment Intents API. Create a PaymentIntent on your server, pass the client secret to the frontend, and use Stripe.js to confirm the payment. This gives full control over the checkout UI while Stripe handles the sensitive payment processing.

Subscription Billing

Stripe Subscriptions manage recurring billing automatically:

  • Create a Customer and attach a payment method.
  • Create a Subscription with the desired price and billing cycle.
  • Stripe automatically charges the customer on each billing cycle.
  • Handle subscription lifecycle events (created, updated, canceled, payment failed) via webhooks.

Webhook Handling

Webhooks are Stripe's way of notifying your application about events. This is the most critical part of payment integration:

  • Verify webhook signatures: Every webhook request from Stripe includes a signature. Verify it to prevent spoofed requests from attackers.
  • Handle idempotently: Stripe may send the same webhook multiple times. Your handler must produce the same result regardless of how many times it is called. Use the event ID for deduplication.
  • Process asynchronously: Return a 200 response immediately and process the event asynchronously. Stripe times out after 20 seconds.
  • Handle critical events: checkout.session.completed, invoice.paid, invoice.payment_failed, customer.subscription.updated, customer.subscription.deleted.

Common Payment Flows

Free Trial → Paid Subscription

Create a subscription with a trial period. Collect payment method during signup but do not charge until the trial ends. Send reminders before the trial ends. Handle the case where payment fails at trial end — the subscription enters a past_due state.

Plan Upgrades/Downgrades

Use Stripe's subscription update API to change plans. Handle proration — when upgrading mid-cycle, charge the prorated difference. When downgrading, credit the unused portion. Stripe handles proration calculations automatically.

Usage-Based Billing

Report usage to Stripe using metered billing. Create a subscription with a metered price, then report usage records throughout the billing period. Stripe calculates the total charge at the end of the billing cycle based on reported usage.

Error Handling

  • Card declined: Show a clear message asking the user to try a different card. Do not expose the specific decline reason from Stripe.
  • 3D Secure authentication: Handle the authentication flow — redirect the user to their bank's 3DS page and process the result.
  • Payment method expired: Notify users when their payment method is about to expire and prompt them to update.
  • Dunning (failed payments): Configure Stripe's Smart Retries and dunning emails for failed subscription payments. Implement grace periods before canceling subscriptions.

Testing

  • Use Stripe's test mode for all development and staging environments.
  • Test with Stripe's test card numbers for different scenarios (successful payment, declined, 3DS required).
  • Use Stripe CLI to forward webhooks to your local development server.
  • Test the complete flow — signup, payment, subscription, upgrade, cancellation, and reactivation.

Conclusion

Payment integration requires careful implementation — PCI compliance, webhook reliability, error handling, and subscription lifecycle management. Use Stripe's hosted solutions (Checkout, customer portal) where possible to reduce complexity. Handle webhooks idempotently and test every payment scenario thoroughly.

Integrating payments? Our team builds secure payment systems across SaaS products.