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. Building a Food Delivery Marketplace on Paystack
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Building a Food Delivery Marketplace on Paystack

Create a Paystack Transaction Split group with the restaurant subaccount (food price share) and rider subaccount (delivery fee share). Pass the split_code when initializing a customer order. Your platform keeps the commission residual. On charge.success, mark the order as paid and notify both restaurant and rider. Rider payouts can be real-time via the split or batched daily via transfers.

In this article

  1. 1. Three-Way Split: Restaurant, Rider, Platform
  2. 2. Order Status via Webhook
  3. 3. Learn More

Three-Way Split: Restaurant, Rider, Platform

// Create a Transaction Split group for an order
async function createOrderSplit(restaurantSubaccount, riderSubaccount, orderTotal, deliveryFee) {
  var restaurantAmount = orderTotal - deliveryFee;
  var platformCommissionRate = 0.08; // 8%
  var restaurantShare = restaurantAmount * (1 - platformCommissionRate);

  var response = await fetch('https://api.paystack.co/split', {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      name: 'Order split',
      type: 'flat', // flat kobo amounts
      currency: 'NGN',
      subaccounts: [
        { subaccount: restaurantSubaccount, share: Math.round(restaurantShare * 100) },
        { subaccount: riderSubaccount, share: Math.round(deliveryFee * 100) },
      ],
      bearer_type: 'account',
    }),
  });
  var data = await response.json();
  return data.data.split_code; // e.g., SPL_xxxxxx
}

// Initialize order payment with the split
app.post('/api/orders', async (req, res) => {
  var { restaurantId, riderId, items, email } = req.body;

  var restaurant = await db.restaurants.findById(restaurantId);
  var rider = await db.riders.findById(riderId);
  var orderTotal = items.reduce((s, i) => s + i.price * i.qty, 0);
  var deliveryFee = 500; // NGN 500

  var splitCode = await createOrderSplit(
    restaurant.subaccount_code,
    rider.subaccount_code,
    orderTotal,
    deliveryFee
  );

  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: Math.round((orderTotal + deliveryFee) * 100),
      split_code: splitCode,
      metadata: { order_id: 'ord_' + Date.now(), restaurant_id: restaurantId },
    }),
  });

  var data = await response.json();
  res.json({ authorization_url: data.data.authorization_url });
});

Order Status via Webhook

if (event.event === 'charge.success') {
  var orderId = event.data.metadata?.order_id;
  if (!orderId) return;

  await db.orders.update({ status: 'paid', paid_at: new Date() }, { where: { reference: event.data.reference } });

  // Notify restaurant to start preparing
  await notifyRestaurant(orderId);
  // Notify rider to go pick up
  await notifyRider(orderId);
}

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 split payments guide.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓A food delivery order splits three ways: restaurant (food), rider (delivery fee), platform (commission) — use a multi-split Transaction Split group.
  • ✓Create a split group per restaurant or use a dynamic split_code generated per order based on current delivery fee.
  • ✓On charge.success webhook, notify the restaurant to prepare the order and the rider to pick it up.
  • ✓Use real-time splits for restaurants but batch weekly rider payouts to reduce transfer costs.
  • ✓Handle order cancellations via Paystack refunds — partial refunds are supported (refund the food price, keep the delivery fee if rider is en route).
  • ✓Store order_id in transaction metadata for webhook handlers to match charges to orders.

Frequently Asked Questions

Do I need to create a new split group for every order?
Only if the amounts differ per order (variable delivery fee, different restaurant). If all orders to the same restaurant have the same split ratio, create the split group once and reuse the split_code. For variable amounts, create a new split group per order.
How do I handle a partial refund when only the food is cancelled but rider already departed?
Use the Paystack refund API with a specific amount (food total only). Paystack partial refunds come from your main account balance — the already-settled subaccount shares are not automatically clawed back. Compensate the rider from your platform balance.
How do I batch rider payouts weekly to reduce transfer costs?
Instead of using a rider subaccount in the split (real-time settlement), route all rider fees to your platform account. Track rider earnings in your database. At end of week, run a bulk transfer to all riders. This reduces transfer count from per-order to per-rider-per-week.
What exchange rate does Paystack use for food delivery platforms charging in USD?
Paystack settles in the transaction currency. For NGN transactions, settlement is in NGN. If you charge customers in USD (for cross-border orders), your subaccounts must also be configured in USD. Most local food delivery platforms charge in local currency.

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 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

Percentage vs Flat Split Configuration on Paystack

A detailed comparison of percentage and flat split configurations on Paystack. Covers how each model works, worked margin calculations across different transaction sizes, when to use percentage vs flat, implementing per-transaction overrides, and building hybrid models that combine both approaches.

Read more

Escrow-Style Flows on Paystack and Their Limits

A thorough analysis of what escrow-style flows you can and cannot build on Paystack. Covers the difference between true escrow and delayed settlement, how to use manual settlement for hold-and-release patterns, the limits around hold duration and fund recovery, regulatory considerations in African markets, and when Paystack is not the right tool for escrow.

Read more

Building an Events Ticketing Platform with Splits

An events ticketing platform collects ticket revenue and routes it to event organizers after the event. This guide covers using Paystack splits to route organizer revenue and platform booking fees, handling multi-ticket types, and managing pre-event holds and post-event payouts.

Read more

Reconciling Payouts Against Recipient Confirmations

A Paystack transfer.success webhook means the money left your balance — it does not mean the recipient confirmed receipt. This guide covers the gap between transfer dispatch and bank confirmation, how to build a reconciliation table, and how to handle disputed or reversed transfers.

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.