
How Stripe billing flows were connected directly to campaign credit behaviour in a brand-creator workflow system.
Context
In this creator marketing platform, campaign delivery depends on credits. That means billing is not a disconnected admin feature. It directly controls whether campaigns can run. The system supported both one-off credit purchases and recurring subscriptions, with Stripe handling payment orchestration and the platform maintaining its own credit ledger and subscription records.
The implementation covered GraphQL billing operations, a Stripe service layer, and an Express webhook route for payment lifecycle events. On the frontend, billing pages exposed balance, transactions, plan state, and top-up flows.
Challenge
Many billing integrations stop at payment success and call it done. Here, that was not enough. A successful payment had to translate into a reliable credit state, an auditable transaction record, and immediate impact on campaign availability.
There were several failure points to guard against. Coupon logic needed to enforce active, expiry, redemption caps, and first-time constraints. Subscriptions needed to prevent duplicate active plans for the same organisation. Webhooks had to verify signatures correctly and process multiple Stripe event types safely. And most importantly, campaigns paused for low credits needed a clean way to resume after funds arrived.
Without this end-to-end linkage, users would pay successfully but still see paused campaigns, or finance records would drift from runtime behaviour.
Approach
We separated concerns with a dedicated StripeService and made the credit ledger updates explicit. The service handles customer creation, one-off purchase intents, subscription creation, plan swaps, cancellation, and resume behaviour. Coupon validation runs through structured checks before prices are adjusted.
For one-off top-ups, purchase records are created in pending state, linked to Stripe payment intents, and finalized on payment_intent.succeeded. Finalization runs in a transaction that marks purchase completion, increments organisation balance, and writes a credit transaction entry with reference metadata.
Subscription renewals follow a similar pattern. On invoice.paid, the system resolves the mapped plan, grants period credits, records a subscription-type credit transaction, and syncs balance changes atomically.
The webhook route uses a raw body parser on the Stripe endpoint so signatures can be verified properly before any event handling runs. Supported event types include payment success, invoice paid, subscription updates, and subscription deletion. Unhandled event types are logged without hard-failing the endpoint.
The final link was runtime behaviour. After credits are added, the Stripe service triggers campaign resume logic so previously out-of-credit campaigns can move back to approved state when balance conditions are met.
Frontend billing screens then surface the same system state: current balance, recent transactions, active plan data, cancel or resume actions, and coupon-assisted purchase flow.
Outcome
Billing moved from a passive record system to an operational control loop. Teams could trust that money-in events actually changed campaign availability in the same flow, with traceable ledger entries and status transitions.
For users, this reduced the friction between payment and delivery outcomes. For support, it reduced the common “I paid but it still looks paused” class of issue. For engineering, it created a cleaner contract between payment events and campaign runtime state.
No inflated performance claims are needed here. The practical outcome was tighter billing-to-delivery alignment, clearer transaction auditability, and less manual intervention after top-ups and renewals.
Key takeaway
In credit-based products, billing integration is only complete when payment events and runtime availability are wired together. Treating Stripe webhooks, credit ledger updates, and campaign state changes as one lifecycle made the system far more dependable.