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. Paystack Subscription Emails: Disabling and Replacing Them
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 20, 2026

Paystack Subscription Emails: Disabling and Replacing Them

Disable Paystack subscription emails by setting send_invoices: false and send_sms: false when creating or updating a plan. Then build your own email notifications triggered by Paystack webhook events (charge.success, invoice.payment_failed, subscription.create, subscription.disable). This gives you full control over branding, content, and timing.

In this article

  1. 1. The Problem with Default Emails
  2. 2. Disabling Paystack Emails
  3. 3. Building Webhook-Driven Email Notifications
  4. 4. Key Email Templates to Build
  5. 5. Avoiding Duplicate Emails
  6. 6. Transitioning from Paystack Emails to Your Own
  7. 7. Notifications for Manual Recurring Charges

The Problem with Default Emails

Paystack sends email notifications to customers whenever a subscription event happens: charge succeeded, charge failed, subscription created, subscription cancelled. These emails are functional but generic. They use Paystack's branding, not yours.

If you also send your own emails for these events (which you should, for a professional product), the customer receives two emails for every event: one from Paystack and one from you. This is confusing, unprofessional, and erodes trust.

The solution: disable Paystack's emails and send your own. You get full control over branding, content, language, and timing. The customer gets one clear notification per event.

This article is part of the subscriptions and recurring billing guide.

Disabling Paystack Emails

Paystack email settings live on the Plan object. When you create a plan, set send_invoices and send_sms to false:

var axios = require('axios');

async function createPlanWithoutEmails() {
  var response = await axios.post(
    'https://api.paystack.co/plan',
    {
      name: 'Pro Monthly',
      amount: 500000,
      interval: 'monthly',
      currency: 'NGN',
      send_invoices: false,
      send_sms: false,
    },
    {
      headers: {
        Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
        'Content-Type': 'application/json',
      },
    }
  );

  var plan = response.data.data;
  console.log('Plan created with emails disabled:', plan.plan_code);
  return plan;
}

For existing plans, you can update the email settings:

async function disableEmailsOnExistingPlan(planCode) {
  var response = await axios.put(
    'https://api.paystack.co/plan/' + planCode,
    {
      send_invoices: false,
      send_sms: false,
    },
    {
      headers: {
        Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
        'Content-Type': 'application/json',
      },
    }
  );

  console.log('Emails disabled for plan:', planCode);
  return response.data.data;
}

Important: These settings affect all subscriptions on this plan. If you disable emails on a plan, no customer subscribed to that plan receives Paystack notifications. Make sure your own email system is working before disabling.

Get weekly developer tips

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

No spam. Unsubscribe anytime.

Building Webhook-Driven Email Notifications

With Paystack emails disabled, you send your own based on webhook events. Here is the mapping:

app.post('/webhooks/paystack', function(req, res) {
  var event = req.body;

  switch (event.event) {
    case 'subscription.create':
      sendWelcomeEmail(event.data);
      break;

    case 'charge.success':
      // Only send receipt for subscription charges, not all charges
      if (event.data.plan && event.data.plan.plan_code) {
        sendSubscriptionReceiptEmail(event.data);
      }
      break;

    case 'invoice.payment_failed':
      sendPaymentFailedEmail(event.data);
      break;

    case 'subscription.not_renew':
      sendCancellationConfirmEmail(event.data);
      break;

    case 'subscription.disable':
      sendSubscriptionEndedEmail(event.data);
      break;
  }

  res.sendStatus(200);
});

async function sendSubscriptionReceiptEmail(chargeData) {
  var customer = chargeData.customer;
  var amount = chargeData.amount / 100; // Convert from kobo
  var currency = chargeData.currency;
  var reference = chargeData.reference;
  var planName = chargeData.plan ? chargeData.plan.name : 'Your subscription';

  await emailService.send({
    to: customer.email,
    subject: 'Payment receipt for ' + planName,
    template: 'subscription_receipt',
    data: {
      customerName: customer.first_name || 'there',
      planName: planName,
      amount: currency + ' ' + amount.toLocaleString(),
      reference: reference,
      date: new Date().toLocaleDateString(),
      manageUrl: 'https://yoursite.com/billing',
    },
  });
}

async function sendPaymentFailedEmail(invoiceData) {
  var customer = invoiceData.customer;
  var cardUpdateUrl = await generateCardUpdateUrl(customer.email);

  await emailService.send({
    to: customer.email,
    subject: 'Action needed: your payment did not go through',
    template: 'payment_failed',
    data: {
      customerName: customer.first_name || 'there',
      cardUpdateUrl: cardUpdateUrl,
    },
  });
}

Key Email Templates to Build

Build these templates to cover the full subscription lifecycle:

1. Subscription Welcome

Triggered by: subscription.create

Content: Thank the customer, confirm the plan and price, state the next billing date, link to billing settings.

2. Payment Receipt

Triggered by: charge.success (for subscription charges)

Content: Confirm the payment amount, show the card charged (last4), state the billing period covered, include the transaction reference, link to download invoice.

3. Payment Failed

Triggered by: invoice.payment_failed

Content: Notify that payment failed, show which card was attempted, include a prominent card update button, explain what happens if not resolved.

4. Upcoming Renewal

Triggered by: invoice.create (optional, some products skip this)

Content: Notify that a charge will happen soon, show the amount, link to manage subscription.

5. Cancellation Confirmed

Triggered by: subscription.not_renew

Content: Confirm the cancellation, state when access ends (end of current period), offer to resubscribe, include a feedback link.

6. Subscription Ended

Triggered by: subscription.disable

Content: Notify that the subscription has ended, explain how to reactivate, assure data is preserved.

Each email should include your logo, follow your brand colors, and link to your billing page. The tone should match your product's voice.

Avoiding Duplicate Emails

Even after disabling Paystack emails, edge cases can cause duplicates or missed emails.

Webhook deduplication

Paystack can send the same webhook event multiple times. If your email handler fires on every webhook, the customer gets multiple copies of the same receipt. Deduplicate by tracking which events you have already processed:

async function processWebhookWithDedup(event) {
  var eventId = event.data.reference || event.data.subscription_code;
  var eventType = event.event;
  var deduplicationKey = eventType + '_' + eventId;

  // Check if already processed
  var existing = await db.query(
    'SELECT id FROM processed_webhook_events WHERE dedup_key = $1',
    [deduplicationKey]
  );

  if (existing.rows.length > 0) {
    console.log('Duplicate webhook skipped: ' + deduplicationKey);
    return;
  }

  // Record before processing
  await db.query(
    'INSERT INTO processed_webhook_events (dedup_key, event_type, processed_at) VALUES ($1, $2, NOW())',
    [deduplicationKey, eventType]
  );

  // Process the event (send email, update database, etc.)
  await handleWebhookEvent(event);
}

Testing before going live

Before disabling Paystack emails on your live plans:

  1. Build and test your email templates on a test plan with emails still enabled.
  2. Verify that your webhook handler sends emails correctly for all event types.
  3. Create a test subscription, let it renew, cancel it, and verify you sent the right emails.
  4. Only then disable Paystack emails on your production plans.

Transitioning from Paystack Emails to Your Own

If you already have customers on plans with Paystack emails enabled, transition carefully:

  1. Build your email system first. Get all templates working, webhook handlers tested, and deduplication in place.
  2. Run both in parallel for a week. Keep Paystack emails on. Send your emails too. Yes, customers get duplicates temporarily, but this lets you verify your system works for all event types.
  3. Disable Paystack emails. Update the plan settings to set send_invoices: false and send_sms: false.
  4. Monitor delivery rates. Check that your emails are reaching inboxes (not spam folders). Monitor bounce rates and open rates for the first few weeks.

If you have multiple plans, you can disable Paystack emails one plan at a time to reduce risk.

Notifications for Manual Recurring Charges

If you use charge_authorization instead of the Subscriptions API, Paystack sends a payment receipt email to the customer by default for each successful charge. This is separate from the subscription email settings.

For manual charges, Paystack's default receipts may be acceptable since they are transaction-level, not subscription-level. But if you want full control, send your own receipt after each charge_authorization call and coordinate with Paystack support about disabling default transaction receipts.

async function chargeAndNotify(userId, amount, authCode, purpose) {
  var user = await getUser(userId);
  var reference = 'BILL_' + userId + '_' + Date.now();

  var result = await chargeAuthorization(user.email, amount, authCode, reference);

  if (result.status === 'success') {
    // Send your own receipt
    await emailService.send({
      to: user.email,
      subject: 'Payment receipt',
      template: 'manual_charge_receipt',
      data: {
        customerName: user.first_name,
        amount: (amount / 100).toLocaleString(),
        purpose: purpose,
        reference: reference,
        date: new Date().toLocaleDateString(),
      },
    });
  } else {
    // Send failure notification
    var cardUpdateUrl = await generateCardUpdateUrl(user.email, userId);
    await emailService.send({
      to: user.email,
      subject: 'Payment did not go through',
      template: 'charge_failed',
      data: {
        customerName: user.first_name,
        cardUpdateUrl: cardUpdateUrl,
        reason: result.gateway_response,
      },
    });
  }

  return result;
}

The goal is always the same: the customer receives exactly one notification per billing event, branded with your logo and voice, with clear information about what happened and what to do next.

Key Takeaways

  • ✓Paystack sends default email notifications for subscription events (charges, renewals, failures). These are functional but unbranded.
  • ✓Disable Paystack emails by setting send_invoices: false and send_sms: false on the plan object.
  • ✓Replace them with your own emails triggered by webhook events. This gives you control over branding, content, and timing.
  • ✓The key webhooks for email triggers are: charge.success (receipt), invoice.payment_failed (dunning), subscription.create (welcome), and subscription.disable (farewell).
  • ✓Always verify that Paystack emails are actually disabled before launching your own. Test with a real subscription to avoid duplicate notifications.
  • ✓Keep Paystack emails enabled during development and initial testing. Only disable them when your own email system is reliable.

Frequently Asked Questions

How do I disable Paystack subscription emails?
Set send_invoices: false and send_sms: false when creating the plan, or update an existing plan with PUT /plan/:code. This stops Paystack from sending email and SMS notifications to customers on that plan.
Can I disable emails for some plans but not others?
Yes. Email settings are per-plan. You can have some plans with Paystack emails enabled (for simple products) and others with emails disabled (for products with custom branded emails).
What happens if I disable Paystack emails but my own email system fails?
Customers receive no notifications at all. This is worse than receiving Paystack's default emails. Only disable Paystack emails after your own email system is tested and reliable. Monitor delivery rates and set up alerts for email system failures.
Does disabling send_invoices also stop the customer management email?
The send_invoices setting controls automatic invoice and receipt emails. The subscription management link (using email_token) is a separate feature. Check Paystack documentation for the exact scope of each setting.
Can I customize Paystack default emails instead of replacing them?
Paystack does not offer customization of their default email templates (adding your logo, changing the text). If you want branded emails, you need to disable the defaults and send your own.

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

Paystack Invoice Events for Subscription Lifecycles

Paystack subscription lifecycles are driven by webhook events. This guide documents every event type, shows the payload structure, explains when each fires, and provides handler code for building a robust subscription state machine on top of Paystack invoice and subscription webhooks.

Read more

Building a Dunning Email Sequence for Paystack Failures

A dunning email sequence recovers revenue from failed recurring charges. This guide walks through the timing, content, and automation of each email in the sequence. Covers the first failure notification, retry updates, card update prompts, and final suspension warnings, with code for automating the entire flow.

Read more

Building a SaaS Billing Page on Paystack

Your SaaS billing page is where customers choose plans, manage subscriptions, view invoices, and update payment methods. This guide covers the complete implementation: Paystack plan setup, the pricing page, the checkout flow, the account billing dashboard, upgrade/downgrade logic, and the APIs that connect it all.

Read more

Cancelling and Pausing Paystack Subscriptions

Paystack lets you cancel subscriptions but has no native pause feature. This guide covers the disable API for cancellation, the difference between immediate and end-of-period cancellation, how to implement pause and resume in your application, and the reactivation flow for customers who come back.

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.