After checkout, react-native-paystack-webview calls your onSuccess callback with the transaction reference. Send this reference to your backend. Your backend calls GET https://api.paystack.co/transaction/verify/:reference with the secret key. Return the result to React Native and navigate to a success or failure screen.
// services/paymentService.ts
const BASE_URL = 'https://your-backend.com';
export interface VerifyResult {
verified: boolean;
amount?: number;
currency?: string;
reference?: string;
error?: string;
}
export async function verifyPayment(reference: string): Promise<VerifyResult> {
try {
var response = await fetch(
BASE_URL + '/api/pay/verify?reference=' + encodeURIComponent(reference),
{
method: 'GET',
headers: { 'Content-Type': 'application/json' },
}
);
var data = await response.json();
if (response.ok && data.verified) {
return {
verified: true,
amount: data.amount,
currency: data.currency,
reference: data.reference,
};
}
return { verified: false, error: data.error || 'Payment not verified' };
} catch (error) {
return { verified: false, error: 'Network error. Please check your connection.' };
}
}
// screens/VerifyPaymentScreen.tsx
import React, { useEffect, useState } from 'react';
import { View, Text, ActivityIndicator, TouchableOpacity, StyleSheet, Alert } from 'react-native';
import { verifyPayment, VerifyResult } from '../services/paymentService';
interface Props {
route: { params: { reference: string } };
navigation: any;
}
export function VerifyPaymentScreen({ route, navigation }: Props) {
var { reference } = route.params;
var [loading, setLoading] = useState(true);
var [result, setResult] = useState<VerifyResult | null>(null);
useEffect(() => {
runVerification();
}, []);
async function runVerification() {
setLoading(true);
var res = await verifyPayment(reference);
setResult(res);
setLoading(false);
if (res.verified) {
// Navigate to success screen after a brief delay
setTimeout(() => {
navigation.replace('OrderSuccess', { reference: res.reference });
}, 1500);
}
}
if (loading) {
return (
<View style={styles.center}>
<ActivityIndicator size="large" color="#4CAF50" />
<Text style={styles.loadingText}>Verifying your payment...</Text>
</View>
);
}
if (!result?.verified) {
return (
<View style={styles.center}>
<Text style={styles.errorTitle}>Verification Failed</Text>
<Text style={styles.errorText}>{result?.error}</Text>
<TouchableOpacity style={styles.retryButton} onPress={runVerification}>
<Text style={styles.retryText}>Retry</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('Support', { reference })}>
<Text style={styles.supportText}>Contact Support</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={styles.center}>
<Text style={styles.successTitle}>Payment Confirmed!</Text>
<Text>{result.currency} {result.amount?.toFixed(2)}</Text>
<Text style={styles.ref}>Ref: {result.reference}</Text>
</View>
);
}
var styles = StyleSheet.create({
center: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24 },
loadingText: { marginTop: 12, color: '#666' },
errorTitle: { fontSize: 20, fontWeight: 'bold', color: '#e53935', marginBottom: 8 },
errorText: { color: '#666', marginBottom: 24, textAlign: 'center' },
retryButton: { backgroundColor: '#4CAF50', padding: 12, borderRadius: 8, marginBottom: 12 },
retryText: { color: '#fff', fontWeight: 'bold' },
supportText: { color: '#666', textDecorationLine: 'underline' },
successTitle: { fontSize: 24, fontWeight: 'bold', color: '#4CAF50', marginBottom: 8 },
ref: { color: '#999', marginTop: 8, fontSize: 12 },
});
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
This guide is part of the Paystack integration guides by language and framework series.
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