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.
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);
}
// 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.
See build a hotel booking and deposit system for the same deposit-then-balance pattern in accommodation.
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