Insurance Premium Collection with Paystack
At policy enrollment, initialize a zero-naira charge or small tokenization payment to get a reusable authorization_code for the customer card. Store it against the policy. On each premium due date, call POST /transaction/charge_authorization with the stored authorization_code and the premium amount. Handle invoice.payment_failed for dunning, and lapse the policy after 3 failed attempts.
Card Tokenization at Policy Enrollment
When a customer signs up for a policy, collect their card and get a reusable authorization code. Use a small charge (e.g., NGN 50) that you refund immediately, or a zero-value charge if Paystack supports it on your account.
// Step 1: Initialize a tokenization payment
app.post('/api/policy/enroll', async (req, res) => {
var { email, policyNumber, premium } = req.body;
var reference = 'enroll_' + policyNumber + '_' + Date.now();
var response = await fetch('https://api.paystack.co/transaction/initialize', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
amount: 5000, // NGN 50 tokenization charge
reference,
metadata: {
policy_number: policyNumber,
action: 'card_tokenization',
},
}),
});
var data = await response.json();
res.json({ authorization_url: data.data.authorization_url, reference });
});
// Step 2: After payment, verify and store the authorization_code
app.post('/api/policy/confirm-enrollment', async (req, res) => {
var { reference } = req.body;
var verifyRes = await fetch(
'https://api.paystack.co/transaction/verify/' + reference,
{ headers: { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY } }
);
var data = await verifyRes.json();
if (data.data.status === 'success') {
var auth = data.data.authorization;
await db.policies.update({
authorization_code: auth.authorization_code,
card_last4: auth.last4,
card_brand: auth.brand,
card_reusable: auth.reusable,
}, { where: { policy_number: data.data.metadata.policy_number } });
// Optionally refund the NGN 50 tokenization charge
await refundTransaction(reference);
res.json({ enrolled: true });
}
});
Dunning and Policy Lapse
// Handle failed charge via charge.failed webhook
if (event.event === 'charge.failed') {
var policyNumber = event.data.metadata?.policy_number;
if (!policyNumber) return;
var policy = await db.policies.findByPolicyNumber(policyNumber);
var failedAttempts = (policy.failed_attempts || 0) + 1;
if (failedAttempts >= 3) {
// Lapse the policy
await db.policies.update({
status: 'lapsed',
lapsed_at: new Date().toISOString(),
failed_attempts: failedAttempts,
}, { where: { policy_number: policyNumber } });
await sendPolicyLapseNotification(policy.customer_email, policyNumber);
} else {
// Schedule retry: +3 days for attempt 1, +7 days for attempt 2
var daysUntilRetry = failedAttempts === 1 ? 3 : 7;
var retryDate = new Date();
retryDate.setDate(retryDate.getDate() + daysUntilRetry);
await db.policies.update({
failed_attempts: failedAttempts,
next_premium_date: retryDate.toISOString().split('T')[0],
}, { where: { policy_number: policyNumber } });
await sendPaymentFailedNotification(policy.customer_email, { failedAttempts, retryDate });
}
}
Learn More
This guide is part of the Paystack recurring billing series.
Key Takeaways
- ✓Tokenize the card at policy enrollment — do not store card numbers. Paystack gives you a reusable authorization_code.
- ✓Use POST /transaction/charge_authorization to charge the stored card on each premium due date.
- ✓Build a scheduled job (cron) that queries due premiums each day and charges them in batches.
- ✓Handle charge failure with a dunning sequence: retry on day 3, day 7, then lapse the policy.
- ✓Send email/SMS notifications before the charge date and immediately on failure so customers can update their card.
- ✓Store the policy_number in the transaction metadata so webhook handlers can match charges to the right policy.
Frequently Asked Questions
- Do I need regulatory approval to collect insurance premiums via Paystack?
- Yes. In Nigeria, Kenya, and Ghana, insurance premium collection requires a license from the relevant insurance regulatory authority (NAICOM in Nigeria, IRA in Kenya). Paystack handles the payment rails, but your business model must comply with insurance regulation. Check with a licensed insurance partner if you are building insurtech.
- What is the difference between Paystack subscriptions and charge_authorization for insurance?
- Paystack subscriptions use fixed plan intervals (monthly, quarterly). Insurance premiums may have irregular amounts (renewal, midterm adjustment), custom due dates, or grace periods. Using charge_authorization directly gives you full control over timing and amount — recommended for insurance use cases.
- How do I handle a customer who wants to update their card?
- Send the customer a link to re-enroll: initialize a new tokenization transaction. When they complete it, update the authorization_code in your database. Old charges continue until the new code is stored. Do not delete the old code until the new one is confirmed as reusable.
- Can I charge a customer before the premium due date if they have insufficient balance?
- No. You cannot pre-charge a card without customer consent for a specific billing period. Send a reminder 3-5 days before the due date and advise them to ensure sufficient card balance. Some insurers send a test authorization a day before the due date, but this requires explicit consent in your terms.
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