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. Build a Vehicle Inspection Booking and Payment App
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Build a Vehicle Inspection Booking and Payment App

Build a vehicle inspection app by managing inspection center slots, requiring fee payment via Paystack before the appointment is confirmed, and issuing a digital inspection certificate (PDF or QR-verifiable record) only after the inspector marks the inspection as completed. Webhook confirms payment; inspector app updates the inspection result and triggers certificate generation.

In this article

  1. 1. Slot Booking and Inspection Fee Payment
  2. 2. Inspection Results and Certificate Generation
  3. 3. Learn More

Slot Booking and Inspection Fee Payment

Tables: centers (name, location, capacity_per_slot, paystack_subaccount_code), inspection_slots (center_id, date, time, booked_count, capacity), inspections (owner_id, vehicle_id, center_id, slot_id, type, fee, status, paystack_ref, certificate_url), vehicles (owner_id, plate_number, make, model, year, color).

var INSPECTION_FEES = {
  annual_roadworthiness: 350000,  // NGN 3,500
  pre_purchase:          500000,  // NGN 5,000
  insurance_valuation:   250000,  // NGN 2,500
};

async function bookInspection(ownerEmail, ownerId, vehicleId, centerId, slotId, type) {
  var fee = INSPECTION_FEES[type];
  if (!fee) throw new Error('Invalid inspection type');

  var slot = await db.inspectionSlots.findById(slotId);
  if (slot.booked_count >= slot.capacity) throw new Error('Slot is fully booked');

  var reference = 'INSP-' + Date.now();
  var center = await db.centers.findById(centerId);

  var inspection = await db.inspections.create({
    owner_id: ownerId, vehicle_id: vehicleId, center_id: centerId, slot_id: slotId,
    type, fee, status: 'pending_payment', paystack_ref: reference,
  });

  var res = 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: ownerEmail, amount: fee, currency: 'NGN', reference,
      subaccount: center.paystack_subaccount_code, // center gets their share
      metadata: { inspection_id: inspection.id, vehicle_id: vehicleId, slot_id: slotId },
    }),
  });
  return (await res.json()).data.authorization_url;
}

// Webhook: confirm inspection slot
if (event.event === 'charge.success') {
  var meta = event.data.metadata;
  if (!meta.inspection_id) return res.sendStatus(200);

  await db.inspections.update(meta.inspection_id, { status: 'confirmed' });
  await db.inspectionSlots.increment(meta.slot_id, 'booked_count', 1);

  var inspection = await db.inspections.findById(meta.inspection_id);
  var vehicle = await db.vehicles.findById(meta.vehicle_id);
  var slot = await db.inspectionSlots.findById(meta.slot_id);
  await sendBookingConfirmation(inspection.owner_id, vehicle.plate_number, slot.date, slot.time);
}

Inspection Results and Certificate Generation

// Inspector submits results via inspector app
async function submitInspectionResult(inspectorId, inspectionId, result, findings, mileage) {
  var inspection = await db.inspections.findById(inspectionId);
  var vehicle = await db.vehicles.findById(inspection.vehicle_id);
  var owner = await db.owners.findById(inspection.owner_id);

  await db.inspections.update(inspectionId, {
    status: result === 'pass' ? 'passed' : 'failed',
    inspector_id: inspectorId,
    findings: findings,
    inspected_at: new Date(),
    mileage_at_inspection: mileage,
  });

  if (result === 'pass') {
    // Generate certificate with unique verification code
    var certCode = 'CERT-' + vehicle.plate_number + '-' + new Date().getFullYear() + '-' + Math.random().toString(36).slice(2, 8).toUpperCase();
    var validUntil = new Date();
    validUntil.setFullYear(validUntil.getFullYear() + 1); // 1-year certificate

    var certificateUrl = await generateCertificatePdf({
      inspectionId, vehicle, owner, certCode, validUntil, mileage,
    });

    await db.inspections.update(inspectionId, {
      certificate_url: certificateUrl,
      certificate_code: certCode,
      certificate_valid_until: validUntil,
    });
    await sendCertificateEmail(owner.email, owner.name, vehicle.plate_number, certificateUrl);
  } else {
    // Failed inspection — send remediation report
    await sendFailureReport(owner.email, vehicle.plate_number, findings);
  }
}

// Public certificate verification (for police/insurers)
async function verifyCertificate(certCode) {
  var inspection = await db.inspections.findByCertCode(certCode);
  if (!inspection) return { valid: false };
  return {
    valid: new Date() < new Date(inspection.certificate_valid_until),
    plate_number: inspection.vehicle.plate_number,
    result: inspection.status,
    valid_until: inspection.certificate_valid_until,
  };
}

Get weekly developer tips

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

No spam. Unsubscribe anytime.

Learn More

See build a barbershop appointment and payment app for a simpler slot booking with deposit pattern without the certificate generation component.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓Payment confirms the slot — no pay, no confirmation, no queue entry.
  • ✓Issue digital inspection certificates only after the inspector marks results as passed or provide a conditional fail report.
  • ✓Support multiple inspection types: annual roadworthiness, pre-purchase inspection, insurance valuation.
  • ✓Use QR codes on certificates for instant roadside verification by traffic police or insurers.
  • ✓For multi-center franchises, use Paystack Subaccounts to route each center's fees automatically.

Frequently Asked Questions

How do I handle vehicle owners who want to reschedule?
Allow rescheduling up to 24 hours before the appointment at no cost — just update the slot_id on the inspection record and adjust the booked_count on both the old and new slots. Within 24 hours, charge a rescheduling fee (NGN 500-1,000) via a new Paystack payment link. No-shows (no reschedule, no cancellation) forfeit the inspection fee.
Can I integrate with NTSA or regulatory systems?
NTSA (Kenya) has an open API for vehicle data and sticker issuance for approved inspection centers. Your app can query NTSA for vehicle registration validity before proceeding with the booking. After a passed inspection, submit the result to NTSA's API to update their records. Regulatory integration requires a formal partnership with NTSA or the relevant motor vehicle authority.
What happens to vehicles that fail the inspection?
Issue a detailed failure report with specific items that failed (e.g., worn brake pads, cracked windshield, expired fire extinguisher). Give the owner a 30-day window to rectify issues and return for a re-inspection at a discounted rate (50% of the original fee). Track failed-and-returned vehicles separately — a high re-inspection conversion rate means your failure reports are actionable and clear.

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

Things You Can Build with Paystack: Project Guides

A complete map of real-world projects you can build using the Paystack API. From online store checkouts and subscription platforms to savings apps and solar pay-as-you-go systems, each category links to step-by-step build guides with working code.

Read more

Build a Parking Payment App

A build guide for a parking payment app where drivers scan a QR code on entry, pay for their session via Paystack (card or M-Pesa), and the system validates payment before the barrier lifts for exit. Covers time-based pricing, session management, and overstay handling.

Read more

Build a Referral Payout System

A build guide for a referral payout system where users share referral links, earn commissions when referrals convert, and withdraw their balance via Paystack Transfers to their bank account or M-Pesa wallet.

Read more

Build a Veterinary Clinic Booking and Payment System

A build guide for a veterinary clinic booking and payment system where pet owners book appointments online, pay a deposit via Paystack to confirm the slot, and pay the balance at the clinic after the consultation. Includes pet health records, vaccination schedules, and automated reminders.

Read more

Paystack Transfers to Paybill and Till Numbers

How to send money to Paybill and Till numbers through Paystack Transfers. Covers recipient creation for both types, the account number format for Paybills, when to use each, code examples in Node.js, and practical reconciliation advice for Kenyan developers.

Read more

Paystack Split Payments and Marketplaces: Complete Guide

Everything you need to split payments on Paystack: creating subaccounts, choosing between percentage and flat splits, multi-split transactions, fee configuration, delayed settlement, escrow-style patterns, and building real marketplace products with working Node.js code.

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.