McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Insurance Premium Collection with Paystack
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

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.

In this article

  1. 1. Card Tokenization at Policy Enrollment
  2. 2. Premium Collection Cron Job
  3. 3. Dunning and Policy Lapse
  4. 4. Learn More

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 });
  }
});

Premium Collection Cron Job

// collect-premiums.js — runs daily at 8am
async function collectDuePremiums() {
  var today = new Date().toISOString().split('T')[0];

  var duePolicies = await db.policies.findAll({
    where: {
      status: 'active',
      next_premium_date: today,
      authorization_code: { notNull: true },
    }
  });

  for (var policy of duePolicies) {
    var reference = 'premium_' + policy.policy_number + '_' + Date.now();

    var response = await fetch('https://api.paystack.co/transaction/charge_authorization', {
      method: 'POST',
      headers: {
        Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: policy.customer_email,
        amount: Math.round(policy.premium_amount * 100),
        authorization_code: policy.authorization_code,
        reference,
        metadata: {
          policy_number: policy.policy_number,
          billing_period: today,
        },
      }),
    });

    var data = await response.json();

    if (data.data?.status === 'success') {
      await db.policies.update({
        last_paid_date: today,
        next_premium_date: getNextBillingDate(today, policy.billing_cycle),
        failed_attempts: 0,
      }, { where: { id: policy.id } });
    } else {
      // Failed — dunning will handle via webhook
      console.error('Premium collection failed for', policy.policy_number, data.data?.gateway_response);
    }
  }
}

function getNextBillingDate(from, cycle) {
  var date = new Date(from);
  if (cycle === 'monthly') date.setMonth(date.getMonth() + 1);
  if (cycle === 'quarterly') date.setMonth(date.getMonth() + 3);
  if (cycle === 'annually') date.setFullYear(date.getFullYear() + 1);
  return date.toISOString().split('T')[0];
}

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

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.

Sign up for the McTaba newsletter

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.

Learn Paystack Integration

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

Not ready? Create Free Account

Keep reading

Paystack Subscriptions and Recurring Billing: Complete Guide

Everything you need to build recurring billing on Paystack. Covers the subscriptions API, plans, authorization codes for manual charges, dunning, lifecycle webhooks, cancellation, and real-world patterns for SaaS, memberships, school fees, and loan collection across Africa.

Read more

Handling Failed Recurring Charges and Dunning on Paystack

Recurring charges fail. Cards expire, accounts run dry, banks decline for opaque reasons. This guide covers every failure scenario in Paystack recurring billing, shows you how to read gateway responses, build a retry strategy, implement a dunning state machine, and handle the higher failure rates typical in African card markets.

Read more

Reusable vs Non-Reusable Paystack Authorizations

Not every Paystack authorization can be charged again. Card payments produce reusable authorizations that work for recurring billing. Bank transfers and USSD produce non-reusable ones. This guide explains the difference, shows you how to check and handle each type, and covers the edge cases across different African payment channels.

Read more

Coupons and Discounts on Paystack Subscriptions

Paystack does not have a native coupon system. To offer discounts on subscriptions, you either create separate discounted plans or manage coupons in your application and charge discounted amounts via charge_authorization. This guide covers both approaches with code examples, coupon validation, and tracking.

Read more

Understanding Kobo, Pesewa and Cents: Paystack Amount Handling

Paystack expects amounts in the smallest currency unit: kobo for Naira, pesewas for Cedis, cents for Rand, Shillings, and Dollars. This guide covers the conversion rules, the floating-point traps that cause wrong charges, and the helper functions that keep your amounts correct.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.