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. Rent Collection with Paystack Recurring Debits
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Rent Collection with Paystack Recurring Debits

At lease signing, tokenize the tenant card with a small authorization charge. Store the authorization_code against the tenancy record. On the first of each month, run a cron job that calls charge_authorization for each active tenancy. On success, trigger a Paystack transfer to the landlord recipient. On failure, notify the tenant and set a grace period before flagging as overdue.

In this article

  1. 1. Tenancy Database Schema
  2. 2. Monthly Rent Collection Job
  3. 3. Learn More

Tenancy Database Schema

CREATE TABLE tenancies (
  id SERIAL PRIMARY KEY,
  tenant_email TEXT NOT NULL,
  tenant_name TEXT NOT NULL,
  authorization_code TEXT,     -- Paystack reusable auth
  card_last4 TEXT,
  property_id INTEGER NOT NULL,
  landlord_recipient_code TEXT NOT NULL, -- Paystack transfer recipient
  rent_amount NUMERIC(12, 2) NOT NULL,   -- Monthly rent in local currency
  service_charge NUMERIC(12, 2) DEFAULT 0,
  currency TEXT DEFAULT 'NGN',
  rent_due_day INTEGER DEFAULT 1,        -- Day of month
  lease_start DATE NOT NULL,
  lease_end DATE NOT NULL,
  status TEXT DEFAULT 'active',          -- active | overdue | terminated
  last_paid_date DATE,
  failed_attempts INTEGER DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

Monthly Rent Collection Job

// collect-rent.js — run on the 1st of each month (or configured due day)
async function collectMonthlyRent() {
  var today = new Date();
  var currentDay = today.getDate();

  var dueTenancies = await db.tenancies.findAll({
    where: {
      status: 'active',
      rent_due_day: currentDay,
      authorization_code: { notNull: true },
      lease_end: { gt: today },
    }
  });

  for (var tenancy of dueTenancies) {
    var reference = 'rent_' + tenancy.id + '_' + today.toISOString().slice(0, 7);

    // Check not already collected this month
    var alreadyPaid = await db.payments.findOne({
      where: { tenancy_id: tenancy.id, reference }
    });
    if (alreadyPaid) continue;

    var totalCharge = tenancy.rent_amount + tenancy.service_charge;

    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: tenancy.tenant_email,
        amount: Math.round(totalCharge * 100),
        authorization_code: tenancy.authorization_code,
        reference,
        currency: tenancy.currency,
        metadata: { tenancy_id: tenancy.id, type: 'rent' },
      }),
    });

    var data = await response.json();

    if (data.data?.status === 'success') {
      await db.payments.create({ tenancy_id: tenancy.id, reference, amount: totalCharge, status: 'paid' });
      await db.tenancies.update({ last_paid_date: today, failed_attempts: 0 }, { where: { id: tenancy.id } });

      // Pay landlord (minus service charge)
      await initiateTransfer(tenancy.landlord_recipient_code, tenancy.rent_amount, tenancy.currency);
    }
  }
}

async function initiateTransfer(recipientCode, amount, currency) {
  return fetch('https://api.paystack.co/transfer', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      source: 'balance',
      recipient: recipientCode,
      amount: Math.round(amount * 100),
      currency,
      reason: 'Monthly rent payment',
    }),
  }).then(r => r.json());
}

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

This guide is part of the Paystack recurring billing series.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓Tokenize tenant card at lease signing — you need a reusable authorization_code to charge each month.
  • ✓Run a monthly cron job on the rent due date. Use charge_authorization, not a Paystack subscription plan.
  • ✓On successful rent charge, immediately initiate a Paystack transfer to the landlord recipient.
  • ✓Keep service charge and management fees from the rent amount before transferring to the landlord.
  • ✓Give tenants a 5-day grace period before marking rent as overdue and sending late payment notices.
  • ✓Store tenancy details in a database: tenant_email, authorization_code, rent_amount, landlord_recipient_code, due_day.

Frequently Asked Questions

Can I charge different amounts each month for rent?
Yes. charge_authorization lets you specify the amount on each call. Unlike Paystack subscription plans which have a fixed amount, charge_authorization is fully flexible. This is useful for rent that varies with utilities, or where the first month is prorated.
What if a tenant disputes the automatic rent charge?
They can raise a dispute with their bank (chargeback). Your strongest defence is a signed lease that authorizes recurring debit, a clear record of when and how much was charged, and a reference tied to a specific billing month. Keep all of this in your database and accessible for dispute resolution.
How do I handle a tenant who wants to change their debit card?
Send them a card update link — initialize a new tokenization charge, verify it, get the new authorization_code, and update the tenancy record. Keep the old code until the new one is confirmed. Never allow tenants to update their own authorization_code directly via your API without authentication.
Should I use Paystack transfers or manual bank transfer to pay landlords?
Paystack transfers (programmatic) are strongly preferred. They are instant, auditable, and trigger a transfer.success webhook. Manual bank transfers require you to log into a banking portal and are error-prone. Create a Paystack recipient for each landlord once and store their recipient_code for all future payouts.

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

Currency Handling in Paystack: NGN, GHS, ZAR, KES and USD

Paystack supports NGN, GHS, ZAR, KES, and USD, but each currency comes with different available payment channels, settlement behaviors, and account requirements. This guide covers what you need to know to handle currencies correctly in your integration.

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.