AI & software engineering studio · Production AI, automation, and systems built to scale

All work
CLIENTMarketplacePaymentsRealtimePayout Engine

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

Manual
Human decision
Automated
AI

Before

  1. Host DMs vendor
  2. Negotiate over chat
  3. Details in a spreadsheet
  4. Service delivered on trust
  5. Vendor invoices after the event
  6. Chase payment

    often unpaid or late

After

  1. Host books a package
  2. Pays upfront (Stripe)
  3. Vendor accepts within 24h

    auto-expires via scheduled job

  4. Per-order chat + photos
  5. Funds settle to wallet
  6. 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

Verified

Domain modules

Isolated backend modules incl. payouts, wallet, finance, disputes, refunds, moderation.

1,238-line schema

Verified

Data model

Single Prisma schema across the marketplace.

3 apps

Verified

Frontends

Customer, vendor, and admin — Next.js 16 / React 19.

Multi-instance

Verified

Realtime scaling

Socket.io + Redis adapter.

2–3 days to bank

Estimated

Payout 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

Next.js 16React 19Tailwind

Backend

Express 5Node.jsTypeScript

Data

PostgreSQLPrisma 7Upstash Redis

Realtime

Socket.ioRedis adapter

Payments

Stripe (payments + payouts)

Integrations

CloudinaryResendPDFKitFirebase

Ops

DockerCI/CDWinstonSwaggernode-cron

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