Build Paystack Subscriptions in Flask
To build Paystack subscriptions in Flask, create a plan via the Paystack API, initialize a transaction with the plan code, handle subscription webhooks to track status, and provide routes for customers to view and cancel their subscriptions.
Subscribe Route
@app.route('/subscribe', methods=['POST'])
def subscribe():
plan_code = request.form.get('plan_code')
email = request.form.get('email')
response = http_requests.post(
'https://api.paystack.co/transaction/initialize',
json={
'email': email,
'plan': plan_code,
'callback_url': BASE_URL + '/subscription/callback',
},
headers={
'Authorization': 'Bearer ' + PAYSTACK_SECRET,
'Content-Type': 'application/json',
},
)
data = response.json()
if data.get('status'):
return redirect(data['data']['authorization_url'])
return 'Subscription failed: ' + data.get('message', ''), 400
Subscription Webhook Handlers
def handle_new_subscription(data):
db.save_subscription({
'subscription_code': data['subscription_code'],
'customer_email': data['customer']['email'],
'plan_code': data['plan']['plan_code'],
'email_token': data.get('email_token', ''),
'status': 'active',
'next_payment_date': data.get('next_payment_date'),
})
def handle_failed_renewal(data):
sub_code = data.get('subscription', {}).get('subscription_code')
if sub_code:
db.update_subscription_status(sub_code, 'past_due')
Cancel Subscription
@app.route('/subscription/cancel', methods=['POST'])
def cancel_subscription():
sub = db.get_user_subscription(current_user.email)
if not sub:
return 'No subscription found', 404
response = http_requests.post(
'https://api.paystack.co/subscription/disable',
json={'code': sub['subscription_code'], 'token': sub['email_token']},
headers={
'Authorization': 'Bearer ' + PAYSTACK_SECRET,
'Content-Type': 'application/json',
},
)
data = response.json()
if data.get('status'):
db.update_subscription_status(sub['subscription_code'], 'cancelled')
return redirect('/dashboard')
return 'Cancellation failed', 400
Gate Content Behind Subscription
from functools import wraps
def subscription_required(f):
@wraps(f)
def decorated(*args, **kwargs):
sub = db.get_user_subscription(current_user.email)
if not sub or sub['status'] != 'active':
return redirect('/subscribe')
return f(*args, **kwargs)
return decorated
@app.route('/premium')
@subscription_required
def premium_content():
return render_template('premium.html')
Subscription Status
@app.route('/api/subscription/status')
def subscription_status():
sub = db.get_user_subscription(current_user.email)
if not sub:
return jsonify({'has_subscription': False})
return jsonify({
'has_subscription': True,
'status': sub['status'],
'plan_code': sub['plan_code'],
'next_payment_date': sub.get('next_payment_date'),
})
Key Takeaways
- ✓Paystack handles all recurring billing. Create plans once and reuse them.
- ✓The first payment creates the subscription. No separate subscription API call is needed.
- ✓Webhook events drive subscription state. Handle subscription.create, charge.success, and invoice.payment_failed.
- ✓Store subscription_code and email_token for managing subscriptions via the API.
- ✓Use Flask decorators or before_request hooks to gate content behind active subscriptions.
- ✓Flask-Login or Flask-JWT-Extended pair well with subscription checks for authenticated access control.
Frequently Asked Questions
- How do I create plans in Flask?
- You can create plans via the Paystack dashboard or by calling POST https://api.paystack.co/plan with the plan name, amount, and interval. Most teams create plans in the dashboard and store the plan codes in their app config.
- Can I offer both monthly and yearly plans?
- Yes. Create separate plans with different intervals and amounts. Let the user choose on your pricing page.
- What happens when a renewal fails?
- Paystack retries the charge. You get an invoice.payment_failed webhook. Update the subscription status to past_due and notify the customer to update their payment method.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon