Verify Paystack Payments in Flask
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.
Verification Helper
# 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}
Verification Route
# 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)
Callback Route with Verification
@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'))
Retry Logic
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
Common Mistakes
- Trusting form data for amounts. Always compare against your database.
- Mixing test and live keys. Both initialization and verification must use the same mode.
- Not checking currency. An attacker could pay in a different currency.
- Granting value before database check. Always check if the order exists and is not already fulfilled.
Key Takeaways
- ✓Verification is a single GET request to the Paystack API using the requests library.
- ✓Create a reusable verify_and_fulfill function for consistent logic across callbacks and webhooks.
- ✓Always check three things: status equals "success", amount matches your database, and currency is correct.
- ✓Use conditional database updates to prevent double-granting when webhook and callback race.
- ✓If the verify request fails, retry. The Paystack transaction state does not change.
- ✓Never trust redirect URL parameters as proof of payment.
Frequently Asked Questions
- Can I verify a transaction multiple times?
- Yes. The Paystack verify endpoint is idempotent. It returns the same result every time.
- What if my verification call fails?
- Retry with exponential backoff. The transaction state on Paystack does not change. The webhook will also deliver the event independently.
- Should I verify in the webhook handler too?
- Yes. Call the same verify_and_fulfill function from both the callback route and webhook handler. The idempotent logic ensures only one fulfills the order.
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