Back to Blog
AI & Software Architecture

SaaS Billing Architecture

Structuring Stripe webhooks, subscription tier models, credit card renewals, and automated email invoice logs.

February 10, 2026 8 min read By Mohammed Ayeenuddin

Stripe Webhooks & Token Buckets

Structuring subscription-based SaaS requires a reliable Stripe webhook handler. We use Express middleware to verify signing signatures and update user quotas in our database dynamically based on payment successes or failures.

The Webhook Idempotency Problem

Stripe may send the same webhook event multiple times. If your system isn't idempotent, a user might receive 3 months of credit for a single payment. We store processed `stripe_event_id`s in a Redis cache or database table to silently ignore duplicate events.

const eventId = stripeEvent.id;
const isProcessed = await db.processedEvents.findById(eventId);
if (isProcessed) return res.status(200).send('Already processed');

await processSubscription(stripeEvent);
await db.processedEvents.insert({ id: eventId });

Handling Failed Payments (Dunning)

When a credit card fails, we don't immediately lock the user out. The architecture must support a 'past_due' status, initiating a Dunning email sequence (Days 1, 3, 7) before automatically downgrading the account to the free tier.