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 Photography Booking and Deposit Flow
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 22, 2026

Build a Photography Booking and Deposit Flow

Build a photography booking system by collecting session details (date, location, type), requiring a 50% deposit via Paystack to confirm the booking, and sending a balance payment link when the gallery is ready for delivery. Store the customer authorization_code from the deposit to charge the balance without making them re-enter card details.

In this article

  1. 1. Booking Form and Deposit Collection
  2. 2. Balance Collection on Gallery Delivery
  3. 3. Learn More

Booking Form and Deposit Collection

Tables: bookings (client_name, client_email, client_phone, session_type, session_date, location, total_price, deposit_amount, balance_due, status, paystack_deposit_ref, authorization_code, gallery_url).

async function createBookingAndDeposit(clientData, sessionDate, sessionType, totalPrice) {
  var deposit = Math.ceil(totalPrice * 0.5); // 50% deposit
  var reference = 'PHOTO-DEP-' + Date.now();

  var booking = await db.bookings.create({
    ...clientData,
    session_date: sessionDate,
    session_type: sessionType,
    total_price: totalPrice,
    deposit_amount: deposit,
    balance_due: totalPrice - deposit,
    status: 'pending',
    paystack_deposit_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: clientData.email,
      amount: deposit,
      currency: 'NGN',
      reference,
      callback_url: 'https://yoursite.com/bookings/confirmed/' + booking.id,
      metadata: { booking_id: booking.id, payment_type: 'deposit', session_type: sessionType },
      label: 'Photography Deposit - ' + sessionType,
    }),
  });
  return (await res.json()).data.authorization_url;
}

// Webhook: confirm deposit and save auth code
if (event.event === 'charge.success' && event.data.metadata.payment_type === 'deposit') {
  var bookingId = event.data.metadata.booking_id;
  await db.bookings.update(bookingId, {
    status: 'confirmed',
    authorization_code: event.data.authorization.authorization_code, // save for balance charge
  });
  await sendBookingConfirmationEmail(bookingId);
}

Balance Collection on Gallery Delivery

// Photographer marks gallery as ready — triggers balance collection
async function deliverGallery(bookingId, galleryUrl) {
  var booking = await db.bookings.findById(bookingId);
  await db.bookings.update(bookingId, { gallery_url: galleryUrl, status: 'gallery_ready' });

  // Option 1: charge balance automatically using saved auth code
  if (booking.authorization_code) {
    var res = await fetch('https://api.paystack.co/charge/authorization', {
      method: 'POST',
      headers: { Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY, 'Content-Type': 'application/json' },
      body: JSON.stringify({
        email: booking.client_email,
        amount: booking.balance_due,
        authorization_code: booking.authorization_code,
        metadata: { booking_id: bookingId, payment_type: 'balance' },
      }),
    });
    var data = await res.json();
    // If auto-charge fails, fall back to payment link email
    if (!data.status) await sendBalancePaymentLink(booking);
  } else {
    // Option 2: send a payment link for the balance
    await sendBalancePaymentLink(booking);
  }
}

async function sendBalancePaymentLink(booking) {
  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: booking.client_email,
      amount: booking.balance_due,
      metadata: { booking_id: booking.id, payment_type: 'balance' },
    }),
  });
  var link = (await res.json()).data.authorization_url;
  await sendEmail(booking.client_email, 'Your gallery is ready!', { link, gallery_preview: booking.gallery_url });
}

The gallery link can be gated behind payment: only show the full resolution photos after balance_due = 0 in your database. Show a watermarked preview with a payment prompt until the balance is cleared.

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 hotel booking and deposit system for the same deposit-then-balance pattern in accommodation.

Sign up for the McTaba newsletter

Key Takeaways

  • ✓A 50% deposit protects against no-shows and last-minute cancellations — collect it at booking confirmation.
  • ✓Store the authorization_code from the deposit to charge the balance without a second checkout flow.
  • ✓Send the balance payment link only when the gallery is ready, not immediately after the session.
  • ✓Implement a cancellation policy: deposit is non-refundable within 72 hours of the session date.
  • ✓For photography marketplaces with multiple photographers, use subaccounts to route each photographer's earnings.

Frequently Asked Questions

Should I gate gallery access behind balance payment?
Yes. Only deliver the full-resolution gallery link after the balance is paid. Show watermarked previews or low-resolution samples to the client after the session to demonstrate the quality, but hold back the deliverable files until payment clears. This is standard practice in photography and protects against clients disappearing after receiving their photos.
What if the client cancels after paying the deposit?
Apply your cancellation policy. If the client cancels more than 72 hours before the session, refund 50% of the deposit (you keep 50% for time already invested in planning). Under 72 hours, the deposit is non-refundable. Use the Paystack Refund API with the deposit transaction reference. Clearly state the cancellation policy in your booking confirmation email and terms.
Can I use this system for a photography marketplace with multiple photographers?
Yes. Create a Paystack subaccount for each photographer. When initializing the deposit or balance payment, include the photographer's subaccount. The photographer gets their share automatically at settlement. Your platform keeps the platform fee. Each photographer can have different commission rates and pricing.

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 an Affiliate Commission Engine

A build guide for an affiliate commission engine where affiliates share tracking links, earn commissions when their referrals convert (pay via Paystack), and withdraw their balance via bank transfer. Covers click tracking, last-click attribution, commission ledger, and Paystack Transfers payout.

Read more

Build a Farmers Market Ordering Platform

A build guide for a farmers market ordering platform where customers order fresh produce from multiple farmers in one cart, the platform collects the combined payment via Paystack, and each farmer receives their share via Paystack Split Payments or Transfers. Covers inventory management, order routing to individual farmers, and delivery coordination.

Read more

Building a Boda Boda Rider Payout System

A complete build guide for a boda boda rider payout system using Paystack Transfers. Covers collecting payments from customers, calculating commissions, creating transfer recipients, disbursing to M-Pesa wallets, handling bulk payouts, managing failures and retries, balance checks, and daily reconciliation.

Read more

Building a Food Delivery Marketplace on Paystack

A food delivery marketplace splits every order three ways: the restaurant gets the food price, the rider gets a delivery fee, and your platform keeps the commission. This guide covers implementing that three-way split with Paystack, handling order status via webhooks, and scheduling rider payouts.

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.