Partylist — Event Vendor Marketplace
A three-sided event marketplace with its own payout engine, disputes, and realtime — built to move real money, not to demo.
Business Context
The situation
Event and party vendors were running their business out of DMs and spreadsheets. Hosts negotiated over chat, bookings lived in someone's inbox, and payment happened on trust. Partylist set out to put customers, vendors, and an operations team on one platform where a booking is paid upfront, tracked to completion, and settled to a real bank account.
The hidden cost
- Vendors chased unpaid invoices after the event was already delivered
- Booking details were scattered across DMs, screenshots, and spreadsheets
- No shared record when a host and vendor disagreed — disputes were he-said-she-said
- Every payout was a manual bank transfer with no audit trail
The Problem
What actually had to be solved
Build a marketplace that can hold money safely between a host paying and a vendor delivering — with upfront payment, a booking lifecycle, per-order communication, and region-specific payouts — across three distinct user experiences (customer, vendor, operations).
Why the existing approach failed
Generic booking tools handle a calendar, not money held in escrow, wallet credits, refunds, or disputes. Off-the-shelf billing bills a customer but has no concept of funds held until a service is delivered, or of an operations team adjudicating a refund. The financial workflow was the product, and it had to be built.
Constraints
- Real money: payment capture, held balances, refunds, and payouts must be correct, not best-effort
- Three separate frontends (customer, vendor, admin) sharing one backend and data model
- Region-specific payouts (Canadian bank transfers) with minimum-threshold rules
- Realtime chat and notifications that keep working as the app scales to multiple instances
Before → After
How the workflow changed
Before
- Host DMs vendor
- Negotiate over chat
- Details in a spreadsheet
- Service delivered on trust
- Vendor invoices after the event
- Chase payment
often unpaid or late
After
- Host books a package
- Pays upfront (Stripe)
- Vendor accepts within 24h
auto-expires via scheduled job
- Per-order chat + photos
- Funds settle to wallet
- Payout to bank
disputes/refunds adjudicated by ops
Architecture
How the system is built
Model the money first. A 1,200+ line data model captures the booking lifecycle, wallet balances, payouts, refunds, and disputes as first-class entities — then three Next.js apps present the right slice of that model to hosts, vendors, and operators. The backend is organised into ~23 domain modules so financial logic (payout engine, wallet, finance, refunds, disputes) is isolated from booking and chat concerns.
Architecture — click any node
Client
API
Orchestration
Integration
Data
Observability
Client
Customer App
Next.js 16 / React 19
- Purpose
- Hosts browse packages, book, pay, and chat.
- Responsibility
- Booking + payment UX and per-order messaging.
- Failure mode
- Degrades to read-only booking history if realtime drops.
AI vs. Engineering
Where AI helps — and where it doesn't
AI Layer
None — deliberately. This is a case study in NOT reaching for AI. A booking timeout, a payout threshold, and a refund rule are deterministic logic; correctness and auditability matter far more than reasoning. AI would have added cost and non-determinism to a system whose entire job is to be predictable with money.
Engineering Layer
Everything: a horizontally-scalable Express API, an append-only wallet ledger, an escrow-style payout engine, a scheduled booking lifecycle, and a Redis-backed realtime layer that survives multi-instance scaling. The dispute and refund workflows give operations a shared source of truth instead of adjudicating from screenshots.
Engineering Decisions
The hard calls, with their tradeoffs
Decision 01
Redis adapter for Socket.io
Choice — Back realtime with a Redis pub/sub adapter rather than in-memory sockets.
Why — Chat and notifications must keep working when the API runs as more than one instance — an in-memory socket map only reaches clients on the same process.
Tradeoff — Adds a Redis dependency and pub/sub complexity, in exchange for realtime that scales horizontally from day one.
Decision 02
Custom payout/wallet engine vs. off-the-shelf billing
Choice — Build the finance layer (holds, wallet ledger, refunds, disputes, payouts) in-house.
Why — A marketplace holds money between payment and delivery and needs region-specific payouts with thresholds — concepts generic billing doesn't model.
Tradeoff — A large, correctness-critical surface to own, in exchange for a financial workflow that actually matches the business.
Decision 03
Scheduled jobs for the 24-hour window — not an agent
Choice — Use node-cron and idempotent state transitions for accept/reject expiry.
Why — A deadline is a rule. Deterministic, cheap, and auditable beats anything probabilistic here.
Tradeoff — Job scheduling to operate, in exchange for behaviour you can reason about exactly.
Cost & Reliability
Built to run, not just to work
Cost strategy
No LLM spend by design. Redis caches hot reads to keep Postgres load low; Upstash and Cloudinary/Resend are usage-priced, so infrastructure cost tracks real booking volume rather than idle capacity.
Reliability
Money-moving writes run inside database transactions; the wallet is an append-only ledger so a failed payout is retried rather than double-paid. The booking lifecycle uses idempotent state transitions, so a missed scheduler tick is recovered on the next run.
Security
Helmet, JWT auth, and Firebase-admin for identity/notifications; financial endpoints are isolated in their own modules with operations-only access for payout and dispute actions.
By the Numbers
What we can point to
~23
VerifiedDomain modules
Isolated backend modules incl. payouts, wallet, finance, disputes, refunds, moderation.
1,238-line schema
VerifiedData model
Single Prisma schema across the marketplace.
3 apps
VerifiedFrontends
Customer, vendor, and admin — Next.js 16 / React 19.
Multi-instance
VerifiedRealtime scaling
Socket.io + Redis adapter.
2–3 days to bank
EstimatedPayout target
Product target for Canadian bank payouts.
Business Impact
System → workflow → outcome
System
A three-app marketplace with upfront payments, realtime, and a payout engine.
Workflow
Hosts pay at booking → vendors accept in 24h → per-order chat → funds settle → payout to bank.
Operational change
Bookings and money move through one auditable system instead of DMs, spreadsheets, and invoice chasing.
Business impact
Vendors get paid reliably and hosts transact with confidence — and the platform can grow booking volume without growing manual operations.
Reflection
Lessons & what we'd do next
Lessons
- Modeling the money first made the three apps fall out of one coherent data model.
- Keeping finance in isolated modules kept the correctness-critical code small and reviewable.
Risks
- Financial logic is correctness-critical — it demands strong test coverage and careful migrations.
- Region-specific payout rules add compliance surface as new regions are added.
Improve next
- Formalise the payout engine as an explicit state machine with replayable events.
- Add contract tests between the shared API and each of the three frontends.
Technology
The verified stack
Frontend
Backend
Data
Realtime
Payments
Integrations
Ops
Could this be relevant to your business?
If you're running bookings, payments, or payouts through spreadsheets and manual transfers — or you need a marketplace that can safely hold money between two sides — this is the kind of system we build.
Related Work
More systems we've built
Voice AI Companion
A production-shaped voice pipeline — speech in, reasoned reply out — with memory, safety, and observability as first-class services, not afterthoughts.
AI Agent Operations Platform
An AI sales/support agent built like infrastructure — services over gRPC and a message queue — to explore what agent operations look like when they're engineered, not scripted.