Project · Event Ticketing

TicketSlinger: Sell Tickets From Your Own Server, and Keep the Fee

Every ticket you sell through a big platform pays somebody else a cut. TicketSlinger is the open-source alternative I'm building in the open: a Go server that sells, emails, scans and refunds tickets, and on your own server takes nothing off the top.

15 minSeats held while a buyer pays
0%Platform fee on your own Stripe
15 KBMost JavaScript an event page may load
AGPL-3.0Open source

Overview

I’ve built ticketing before. In 2009 a traveling midway wanted to sell fair admission online and stop printing paper, and no product did it, so I built one: QR tickets, phone apps for the gate, a code that let you in once and only once. Seventeen years on, the hard parts haven’t moved. Two people want the last ticket at the same second. Two doors scan the same screenshot.

What has changed is who gets paid. Sell a $20 ticket through one of the big platforms and a slice of every one goes to them, on top of the card fee, whether you’re a stadium or a village hall.

TicketSlinger is my answer to that, and the GitHub description is honest about where it stands: the world’s greatest open-source ticket selling platform in the making. The first release went out on 19 October 2026. This page says what works today and doesn’t pretend about the rest.

The problem

Selling a ticket looks simple until two buyers want the last one. Get the locking wrong and you’ve sold a seat that doesn’t exist, and now somebody at the door has a valid-looking QR code and nowhere to stand.

The door has the same problem in reverse. A ticket forwarded to three friends is three scans of one code. If your scanner checks “has this been used?” and then, a moment later, writes “used”, two doors can both say yes.

And then there’s the fee, which you pay on every sale, forever, for software you could run yourself.

What I built

A Go API over PostgreSQL, with a storefront and an organizer dashboard on Bun. You create an event, give it ticket types, and put quotas on them. A buyer picks tickets and the server holds them for 15 minutes while they pay. Card payments go through Stripe; when the payment lands, the buyer gets an email with a PDF, one ticket to a page, and a link to their order.

Organizers get what they’d go looking for in week two: promo codes, hidden ticket types that only an access code reveals, questions asked once per order or of every attendee, refunds, a sales report and CSV exports. Sign-in takes a password or a passkey, with an authenticator app as a second step if you want one. API keys are there for anyone who’d rather script it.

The event page is kept deliberately light. The test suite fails it if it loads more than 15 KB of JavaScript, and Cloudflare’s bot check isn’t fetched until the buyer starts filling in the form.

Two things it won’t do

It won’t oversell. Every checkout locks the quotas it draws from, always in the same order, and checks they have room counting both sold tickets and live holds. If a hold expires while a checkout is waiting for the lock, it still counts. Any mistake leans towards turning a buyer away, never towards selling a seat twice.

It won’t let one ticket in twice. Check-in is a single guarded database update, so when two doors scan the same code at the same moment, one gets “accepted” and the other gets “duplicate”, with the time it was first used. Gate staff scan with the phone they already have: the dashboard uses the browser’s own QR reader, and falls back to a WebAssembly one where there isn’t a built-in reader. A scanned code is logged only as a hash, never as the code itself.

Underneath both sits one more rule. Every write to the API accepts an idempotency key, and the checkout sends one, so a buyer on a bad connection who taps Pay twice is charged once.

Selling on your own server

Here’s the part that matters to me most. Run TicketSlinger yourself with TS_PAYMENTS=direct and four Stripe variables, and buyers pay straight into your Stripe account. No platform fee. Set one anyway and the server won’t start. You pay Stripe’s card fee and nothing else.

Email goes out through Resend or your own SMTP server, and TLS isn’t optional: a mail server that only speaks plaintext never sees a buyer’s ticket link.

Where it is now

Early, and I’d rather say so. Version 0.1.3 shipped on 20 October, the fifth release in two days. Self-hosting runs on one Linux box with Docker Compose and a reverse proxy you already trust; Docker Desktop on a Mac or Windows won’t run that file, because it uses host networking. A Cloudflare Turnstile key is required for a public site.

What it doesn’t do yet matters too. Every ticket is general admission, with quotas to cap the numbers, so there are no seating plans. Buyers get a PDF and an order page, not wallet passes. And the README is still short: if you try it this week, expect to read the comments in deploy/.env.example.

Try it

On a Linux server with Docker:

git clone https://github.com/ticketslinger/ticketslinger
cd ticketslinger
cp deploy/.env.example deploy/.env    # fill it in
docker compose -f deploy/compose.yaml up -d --build

Compose starts PostgreSQL, runs the migrations, then brings up the API, the storefront and the dashboard on 127.0.0.1. The code, the OpenAPI spec and every release are on GitHub.

// Let's talk

You have ideas.
I have IT solutions.

Fifteen minutes on Zoom is usually enough to tell whether I'm the right person for what you're building.

Denver, CO · Available for architecture, infrastructure, and DevOps engagements