How to Set Up Recurring Subscription Billing With Paystack and Flutterwave
A one-off payment and a subscription are, technically, quite different problems, and a lot of confusion in building recurring billing comes from treating them as the same task with a repeat button attached. This guide covers how subscription billing actually works on Paystack and Flutterwave, the specific things that go wrong that do not exist in a simple checkout, and how to design a subscription flow that survives real customers over real months, not just a clean first charge.
What actually changes between a one-off payment and a subscription
In a one-off payment, covered in our Paystack and Flutterwave tutorials, a customer authorises and completes a single transaction, and the relationship between you and their card ends the moment that transaction settles. A subscription requires the customer to authorise your business to charge their card again in the future, without them being present or re-entering their details each time, which means your system needs to securely reference their payment method for later use, and needs to handle every outcome a repeated charge can produce over time: a card that expires between cycles, a payment that fails on a specific renewal, a customer who wants to cancel partway through a period they already paid for.
Setting up a plan: the structure both gateways use
Both Paystack and Flutterwave organise recurring billing around a plan, a defined structure specifying the amount, the currency, and the billing interval, monthly, weekly, or another cycle you define, created once in your dashboard or through the API before any customer ever subscribes to it. A customer subscribing to a specific plan authorises their card during an initial checkout, and the gateway then handles automatically charging that same card at each subsequent interval according to the plan's defined schedule, without your application needing to manually trigger every single renewal charge itself.
The first charge: where genuine authorisation actually happens
The customer's very first payment against a subscription plan is where their card is genuinely authorised for future charges, and this first transaction needs to be treated with real care, following the same verification discipline covered throughout our payment guides: verify the transaction's actual status through the gateway's API after checkout, rather than trusting a redirect alone, before treating the subscription as genuinely active. A subscription record created before the first payment is confirmed successful risks granting access to a service the customer has not actually, successfully paid for yet.
Handling a failed renewal, which will happen regularly
Unlike a one-off checkout, where a failed payment simply means the customer did not complete a purchase, a failed subscription renewal is a genuinely different, more delicate situation: an existing customer, already using your service, whose card failed to charge on a scheduled date, for reasons ranging from insufficient funds to an expired card to a bank's own temporary block. Build an explicit, planned response to this rather than treating it as an edge case: notify the customer promptly and clearly, offer a straightforward way to update their card details, and decide a sensible grace period before actually suspending their access, rather than either cutting off a paying customer's access the instant one renewal fails, which reads as unnecessarily harsh for what may be a simple, temporary issue, or ignoring failed renewals entirely, which quietly erodes your actual revenue as failed charges accumulate unnoticed.
Webhooks: where a subscription's actual state lives
Both gateways notify your application of subscription events, a successful renewal, a failed charge, a cancellation, through webhooks, following the same general pattern and the same signature verification discipline covered in our guide to what a webhook is. This matters more for a subscription than for a one-off payment, because a subscription's true, current status genuinely changes over time, entirely outside any single request your own application initiated, and your application needs to stay correctly synchronised with that changing state through webhooks arriving on their own schedule, not just at the moment a customer is actively interacting with your site.
Cancellation: making it genuinely easy, on purpose
It is tempting, from a pure revenue perspective, to make cancelling a subscription deliberately awkward, and this is worth resisting directly. A customer who wants to cancel and finds the process frustratingly difficult does not usually become a retained, satisfied customer, they become a customer who disputes the next charge with their bank instead, which costs you more in dispute fees and reputation than the retained revenue from one more difficult-to-avoid cycle was ever worth. Build a genuinely clear, easy cancellation path, and treat a low-friction cancellation process as a trust signal that, counterintuitively, supports rather than undermines a subscription business's long-term health.
Proration and mid-cycle changes
If your business allows a customer to upgrade or downgrade their subscription plan partway through a billing cycle, decide explicitly how this is handled: does the customer pay a prorated difference immediately, or does the change simply take effect at the next renewal. Neither answer is universally correct, and the wrong one, chosen by default rather than deliberately, produces confused customers disputing a charge that does not match what they expected. State your actual policy clearly to the customer at the point of making a change, rather than leaving them to discover how it was handled only once their next statement arrives.
How Flutterwave's approach differs specifically
Flutterwave's recurring billing follows a broadly similar shape to Paystack's, plans, tokenised card authorisation, automatic scheduled charging, with its own specific API surface and its own webhook event names for subscription-related events, distinct from Paystack's naming, worth reading directly from Flutterwave's current documentation rather than assuming identical structure purely because the underlying concept is the same. If you are supporting both gateways, covered across our Paystack and Flutterwave tutorials, build your own internal subscription model as the single source of truth in your own database, translated to and from each gateway's specific API shape, rather than letting either gateway's particular structure leak directly into how your own application reasons about a customer's subscription status.
Dunning: the practice of recovering a failed payment gracefully
The broader practice of managing failed renewal attempts, notification, retry timing, and eventual suspension, has a name in the payments industry, dunning, and it is worth treating as a genuine, designed process rather than an afterthought. A reasonable dunning sequence might notify the customer immediately on a failed charge, retry automatically after a short delay in case the failure was purely temporary, send a second, more direct notice if the retry also fails, and only suspend access after a final, clearly communicated deadline the customer had real, fair warning about. Both gateways offer some automatic retry behaviour of their own, worth understanding specifically rather than assuming, and layering your own clear customer communication on top of whatever automatic retry the gateway itself performs, since a silent, gateway-only retry with no customer-facing notice leaves the customer with no idea anything is wrong until access is already suspended.
Currency and international subscribers
If your subscription business serves customers outside Nigeria, decide explicitly whether to bill in naira, letting an international customer's own bank handle the currency conversion, or in their local currency directly, which some gateway configurations support, covered by Flutterwave's stronger general international currency handling noted in our Flutterwave tutorial. Neither choice is universally correct, and the right one depends on your specific customer base's expectations and how sensitive your actual margins are to exchange rate movements between when a subscription was priced and when each individual renewal actually settles.
Reporting and reconciliation for a subscription business specifically
A subscription business's financial reporting is genuinely more complex than a simple one-off sales business, since revenue recognised in a given month may relate to a subscription period spanning into the next, and a cancelled subscription part-way through a paid period raises questions about whether any refund is owed for the unused remainder, a policy worth deciding explicitly and stating clearly to customers rather than improvising differently for each individual cancellation request. Build a regular, deliberate habit of reconciling your own subscription records against the gateway's actual settled transactions, similar to the reconciliation discipline covered in our broader payment troubleshooting guides, specifically checking for subscriptions your own system shows as active that the gateway's records show as having failed or lapsed, which is exactly the kind of quiet, costly gap that accumulates unnoticed without deliberate, regular checking.
Free trials, if your business offers one
A free trial before the first charge introduces its own specific design question: does the trial require card details upfront, converting automatically into a paid subscription once the trial ends, or does it require no payment information at all, needing the customer to actively choose to subscribe once the trial concludes. The first approach captures more customers who forget to actively cancel, converting more of them into paying subscribers, and it also produces more disputed charges from customers who genuinely did forget and feel surprised by an unexpected charge. The second approach converts fewer trial users into paying customers but produces a customer base that chose deliberately to pay, generally with fewer disputes and better long-term retention. Choose deliberately based on your own business's actual values and risk tolerance here, rather than defaulting to whichever pattern happens to be most common without considering which genuinely fits your specific product and customer relationship.
A worked example: an imagined online course platform
Picture a small platform selling monthly access to a set of online courses, using Paystack's subscription plans for billing. The first version, built quickly, correctly charges customers monthly and correctly grants access on a successful payment, and has no explicit handling for a failed renewal at all beyond Paystack's own default retry behaviour, which the founder had not actually read closely enough to understand.
Within the first two months, a meaningful number of customers experience a failed renewal, mostly ordinary card expirations and temporary bank declines, and because there is no specific notification or grace period built in, several genuinely willing, paying customers lose access abruptly with no warning and no easy way to fix it themselves, several of whom simply leave rather than figure out how to resubscribe. Adding an explicit failed-renewal flow, a clear email and in-app notice the moment a webhook reports a failed charge, a three-day grace period before access is actually suspended, and a one-click way to update card details, recovers a meaningful share of what would otherwise have been entirely avoidable churn, from customers who were never actually trying to leave, just caught by an ordinary card expiration nobody had told them about.
A short checklist before launching subscription billing
The first charge is verified through the gateway's API before access is granted, not just trusted from a redirect. A failed renewal triggers a clear, timely customer notification, not silence. A sensible grace period exists before suspending access, stated clearly to customers in advance. Cancellation is genuinely easy to find and complete. Webhooks are properly signature-verified and drive your own subscription status, rather than your application guessing based only on what a customer last saw in their browser. And the whole lifecycle, first charge, successful renewal, failed renewal, cancellation, has been tested deliberately in sandbox mode before any real customer's card is charged against it.
Mistakes specific to subscription billing
Treating the first charge exactly like every subsequent renewal. The first charge is where authorisation genuinely happens and deserves the same careful verification as any one-off payment; renewals rely on that already-established authorisation and behave somewhat differently.
No explicit plan for failed renewals. This is the single most common gap in a first subscription implementation, and it directly costs genuine, willing customers through nothing more than an unhandled, entirely ordinary card expiration.
Making cancellation deliberately difficult. This trades a small amount of short-term retained revenue for a larger, longer-term cost in disputes and reputation.
Not testing the full subscription lifecycle in sandbox mode. Test a successful first charge, a successful renewal, a deliberately failed renewal, and a cancellation, all in test mode, before trusting the flow with real, paying customers.
Where this is already built for you
If your business model fits one of our existing templates rather than needing bespoke subscription logic, our platform's own recurring elements, project plan tiers, VTU pricing structures, already handle this discipline internally. For a genuinely custom subscription product, our custom software service can help design and build the specific billing lifecycle your business needs, and our Paystack and Flutterwave tutorials cover the underlying one-off payment integration this subscription layer builds on top of.




Comments
No comments yet. Be the first to share your thoughts.