Back to Blog

Zendini: Building a Ticketing Platform for a 538-Seat Theater

July 11, 2026Jeff Conn
Building in PublicZendiniTicketingCustom Software

The Amish Country Theater seats 538 people a night. Selling those seats is the whole business — and the buying experience is the first impression every guest gets, before the lights go down, before the first joke lands. I wanted that experience to feel like ours: the theater's brand, one clean page per show, a seat picker that works on a phone, and a box office that staff can learn in an afternoon.

Zendini is the ticketing platform I built to do that. It's named like a magician because pulling this off felt like one.

The Zendini storefront — show artwork cards on the theater's branded home page.

Getting the data model right first

The foundational decision was the event model. A show isn't a date — it's a show, with many performances. In Zendini, "Elvis Forever" is one event with its own artwork, description, and video, and under it live dozens of performances that share everything by default. Master pricing is set once on the event; any individual performance can override a tier for one date without touching the rest. Change a show's description and it changes everywhere, instantly.

Pricing templates — master prices set on the event, with a single date override pinned.

538 real seats

The seat picker renders the actual venue — six sections, every row and seat in its true position, drawn as an interactive SVG with color-coded price tiers and live availability. Picking your exact seat from your phone is the moment online ticketing either feels modern or doesn't.

The seat picker — the theater's real 538-seat layout with color-coded price tiers.

Under the map is the part nobody sees: two people tapping the same seat at the same moment. Seats get a ten-minute hold during checkout, and the final claim happens inside a single database transaction guarded by a unique index — if two checkouts race, exactly one wins and the other gets a clear message instead of a double-sold seat. Payment confirmation is asynchronous: the payment processor's webhook finalizes the order server-side, so a closed laptop lid mid-purchase can't strand a sale in limbo.

The box office is a product too

Half of ticket sales don't start on the website — they're phone orders, walk-ups, comps, and group bookings. So Zendini has a staff-facing point of sale: a today-view dashboard, one unified selling flow for reserved seating and general admission, refunds with reason codes, will-call pickup lists, and QR-coded tickets scanned at the door.

The box-office sell screen — seat map plus cash, card, and comp order handling.

Group sales got real engineering attention because they're how theaters actually fill Tuesday nights: a tour operator puts down a deposit — flat or percentage — then pays the balance in as many partial payments as they need, with the balance tracked and unpaid holds lapsing back into sellable inventory automatically.

The admin event summary — sales, revenue by type, and performance pacing at a glance.

Two design languages, one system

The storefront wears the theater's identity — its green, its type, big show artwork, mobile-first. The back office uses what I call the calm kit: navy and glacier blue on off-white, Poppins and Inter, generous whitespace, dense only where staff need density. Guests get a branded experience; staff get a tool that stays out of the way at 6:45pm with a line at the window.

The stack

Next.js 16 on Vercel, Postgres with row-level security on Supabase, Stripe for payments, Resend for ticket delivery, QR codes generated per ticket. The schema is multi-tenant from the first table — organizations own venues, venues own seat maps — so the theater is tenant number one rather than a hardcoded assumption. Eighty commits over about a month, built by me and a squad of AI coding agents, with the seat-hold race conditions and payment webhooks getting the human attention they deserve.

Zendini hasn't launched yet — it's in final pre-launch hardening: live payment keys, the ticketing domain, and the data migration are the last mile. I'm targeting Q1 2027 for the cutover, which is a natural break in the theater's calendar between seasons. The next season goes on sale through it.