To verify a Paystack payment in Flask, make a GET request to https://api.paystack.co/transaction/verify/:reference using the requests library. Check that the status is "success", the amount matches your stored order, and the currency is correct. Use a database update with a condition to prevent double-granting.
# helpers.py
import os
import requests
PAYSTACK_SECRET = os.environ.get('PAYSTACK_SECRET_KEY')
def verify_transaction(reference):
response = requests.get(
'https://api.paystack.co/transaction/verify/' + reference,
headers={'Authorization': 'Bearer ' + PAYSTACK_SECRET},
)
return response.json()
def verify_and_fulfill(reference, db):
order = db.get_order(reference)
if not order:
return {'error': 'Order not found'}
if order['paid']:
return {'success': True, 'already_fulfilled': True}
result = verify_transaction(reference)
if not result.get('status') or result['data']['status'] != 'success':
return {'error': 'Payment not successful'}
if result['data']['amount'] != order['amount_kobo']:
return {'error': 'Amount mismatch'}
if result['data']['currency'] != order['currency']:
return {'error': 'Currency mismatch'}
updated = db.mark_paid(reference)
if not updated:
return {'success': True, 'already_fulfilled': True}
return {'success': True, 'amount': order['amount_kobo'] / 100}
# app.py
from flask import request, jsonify
from helpers import verify_and_fulfill
@app.route('/api/verify')
def verify_payment():
reference = request.args.get('reference')
if not reference:
return jsonify({'error': 'Missing reference'}), 400
result = verify_and_fulfill(reference, db)
if result.get('error'):
return jsonify(result), 400
return jsonify(result)
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
@app.route('/payment/callback')
def payment_callback():
reference = request.args.get('reference') or request.args.get('trxref')
if not reference:
return 'Missing reference', 400
result = verify_and_fulfill(reference, db)
if result.get('success'):
return render_template('success.html', reference=reference)
return render_template('failed.html', error=result.get('error', 'Unknown'))
import time
def verify_with_retry(reference, max_retries=3):
for attempt in range(max_retries):
try:
result = verify_transaction(reference)
if result.get('status') is not None:
return result
except requests.exceptions.RequestException:
pass
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
return None
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course