appycodes.

Case study · UK · Event ticketing

Ontick: a custom Laravel ticketing platform, Stripe instalment payments, and two mobile apps.

Off Eventbrite, off platform commissions, on to a fully owned ticketing stack: multi-organizer, with Stripe-orchestrated instalment payments, QR tickets released only on full settlement, a venue-side check-in app, and a customer app. £2M+ in sales generated to date, with the engagement ongoing.

Client

Event ticketing
Ontick logo

Ontick, event ticketing platform

Surfaces shipped

  • Web platform, organizer plus customer
  • Check-in mobile app for venue staff
  • Customer mobile app on iOS and Android
StackLaravel · Vue · MySQL · React Native

Numbers from the work

£2M+

Sales generated through the platform since launch

Multi-organizer

Super admin plus per-organizer events, by default

Stripe instalments

Automated, idempotent, recovery built in

3

Surfaces shipped: web plus check-in app plus customer app

The platform

A fully owned Laravel ticketing stack, public to back-office.

Ontick web platform: public event page and booking flow built on Laravel
The Ontick web platform: public-facing event pages, multi-organizer back-end, and the booking flow that feeds the Stripe-orchestrated instalment engine.

How the engagement started

An Eventbrite margin problem worth solving in code.

Ontick came to us running their events on Eventbrite. The experience was fine for buyers, the operational tooling was fine for staff, but the commission Eventbrite took on every ticket was the largest fixed cost on the business. At the volume Ontick was already running, the percentage they were paying made a custom platform a clearly positive ROI decision rather than a vanity project.

The brief was specific: a custom booking platform with a rich public front-end and a full back-end for the team, on a stack the client could own end-to-end. One feature was non-negotiable from day one: tickets had to be purchasable in instalments, with the QR codes only released after the final payment landed. That single requirement set the architectural agenda for everything that followed.

TL;DR

  • Migrated off Eventbrite onto a fully owned Laravel platform, eliminating the per-ticket commission that was the original reason for the engagement.
  • Multi-organizer architecture by default: a super admin creates organizers; each organizer creates events with multiple ticket types, per-tier inventory, and per-tier sale windows.
  • Stripe-orchestrated instalment payments with strict guarantees: QR tickets are not released until the full balance settles; every instalment is idempotent against duplicate charges; failed payments recover automatically.
  • Two React Native mobile apps on top of the platform: a venue-side check-in app tuned for speed (thousands queuing) and a customer app with push notifications for upsell, reminders and recovery.
  • £2M+ in sales processed through the platform to date; the engagement is ongoing.

Stage 1 · Custom Laravel platform

Multi-organizer from day one, not retrofitted.

The platform is built end-to-end on Laravel: the public booking surface, the organizer back-end, the super-admin back-end, and the REST API the mobile apps later consumed. One framework, one team, one deploy.

The multi-organizer model was the most consequential architectural choice. A super admin can create any number of organizer accounts; each organizer manages their own events, ticket inventory, sale windows and payouts. Events themselves support multiple ticket tiers with independent pricing, capacity, and on-sale or off-sale dates. The data model was designed for this from day one rather than retrofitted, which is usually where multi-tenant ticketing platforms run into compounding problems later, as we cover in our companion multi-tenant architecture cost study.

Stage 2 · Stripe-orchestrated instalments

Instalments look simple from the outside. They are not, in production.

Each charge is a network call that can fail, succeed slowly, succeed twice, or end up in an ambiguous state. Each ticket can be in any of those states at any point in its payment lifecycle. The engineering job is to keep the system in a known-good state at every step. The shape we shipped:

01

Stripe handles the actual capture

We store payment methods via Stripe's tokenised flow and orchestrate the schedule from our side, calling Stripe's API when each instalment is due.

02

QR tickets are held back until full settlement

A booking can be paid down over months; the customer gets confirmation and a schedule at booking time, but the actual ticket QR is only minted and emailed once the final instalment posts. This is the single most important business rule and it is enforced in code, not in policy.

03

Idempotency on every payment touchpoint

Every charge uses a Stripe idempotency key derived from the booking id and instalment index. The webhook handler insert-on-conflicts against an event-id-primary-key table before doing any work, so the same Stripe event arriving twice produces exactly one state change.

04

Automated failed-payment recovery

A failed charge enters a retry schedule with backoff, customer notifications at sensible intervals, and a soft-delete path for bookings that never recover. The operations team see what is happening but do not have to touch it for routine failures.

05

Duplicate-charge protection

Beyond idempotency keys, we layered defensive checks: booking-level locks during a payment attempt, a guard on the webhook side that refuses to mark a booking paid past its total, and a daily reconciliation cron that compares our ledger to the Stripe balance transactions.

The idempotency and reconciliation discipline is the same pattern we wrote up in our companion Stripe webhooks reference architecture post.

Ontick checkout: ticket selection, instalment schedule and Stripe payment in a custom Laravel flow
The checkout surface where instalment schedules are composed, the first payment is captured, and the rest of the schedule is set up against the stored payment method.

Stage 3 · Check-in app for venue staff

One design constraint: speed. Each check-in lands in under a second.

Once the platform was generating real ticket volume, the next operational pain point surfaced quickly: door staff were checking in attendees from a browser-based view that was not built for the queue tempo of a real event. We shipped a dedicated check-in app built in React Native consuming the same Laravel REST API. The decisions that earn that latency:

01

Offline-first scan path

The app caches the full attendee list for the event on session start. Scanning resolves locally; the network round-trip happens in the background to mark the attendee server-side. The door operator never waits on the API.

02

One-tap operation

Open camera, scan, green tick, scan the next. No confirmation dialogs, no navigation. Edge cases (already-checked-in, wrong event, comp ticket) surface inline without breaking the flow.

03

Bluetooth-scanner support

For staff who prefer dedicated hardware over the camera.

04

Role-scoped login

A staff member can only check in attendees for events they are assigned to. Permissions live on the API side, not the app.

Stage 4 · The customer app

The booking experience in the buyer's pocket, with messaging as the unlock.

Most recently we shipped a customer-facing React Native app that gives the buyer the entire booking experience at their fingertips: browse, book, schedule instalments, access tickets. The bigger commercial unlock is the messaging layer. Push notifications power three flows that previously sat in email and underperformed:

Upsell

Targeted offers for upgrade tickets, add-ons or partner events, segmented by the customer's booking history.

Failed-payment recovery

A push lands within minutes of an instalment declining, with a one-tap path back into the app to retry. Conversion on this channel is materially higher than the equivalent email recovery sequence.

Upcoming payment schedule reminders

A heads-up before the next instalment is due, with the option to swap the payment method without leaving the app.

The push infrastructure itself is the same pattern we wrote up in our companion push notifications on Expo plus FCM plus APNs post, with the same focus on real delivery measurement rather than ticket-success rates.

Ontick customer app: React Native booking experience with push notifications for upsell, recovery and instalment reminders
The customer-facing app: browse, book, manage instalment schedules and access tickets in one place.

Outcomes

Where the engagement stands today.

  • £2M+ in sales processed through the Ontick platform since launch.
  • Zero platform commissions: every pound of ticket revenue stays with the organizers, minus Stripe's payment-processing fees.
  • Multi-organizer architecture running in production, with new organizers onboarded by the super-admin team without engineering involvement.
  • Instalment-payment engine running cleanly, including the duplicate-protection, idempotency, and automated-recovery guarantees, none of which have generated a real-world incident to date.
  • Two production mobile apps: the check-in app used at every event, the customer app live on iOS and Android.
  • The engagement is ongoing: we run the platform day-to-day, ship new features alongside the client's product team, and own the post-launch observability and recovery flows.

Stack summary

One Laravel core, two React Native apps, Stripe underneath.

Web platform
Laravel (PHP): public booking, organizer back-end, super admin, REST API
Frontend (web)
Blade plus Vue.js components, hand-audited bundle
Database
MySQL with multi-organizer schema, booking plus instalment ledger
Payments
Stripe: tokenised payment methods, idempotency-keyed charges, webhook-driven reconciliation
Scheduled jobs
Laravel queues plus scheduler: instalment runs, failed-payment retries, daily Stripe reconciliation
Check-in app
React Native (iOS plus Android), offline-first scan cache, Bluetooth-scanner support
Customer app
React Native (iOS plus Android), Expo plus FCM plus APNs for push, deep links
Observability
Structured request logging, Stripe-event ledger, push-delivery instrumentation

Where it shipped

A live, ongoing engagement.

Live engagement

The Ontick platform is live, processing instalment bookings across multiple organizers, with the check-in app running at every event door and the customer app live on the iOS and Android stores. £2M+ in sales generated to date, with the per-ticket commission that drove the original brief now sitting at zero.

The engagement is ongoing: day-to-day platform support, new feature work, post-launch observability and payment reconciliation are all owned by us.

Building something in this shape? The three engagements that map directly to the Ontick rebuild: SaaS web app development, React Native app development, and maintenance and support.

Got an Eventbrite-style margin problem?

Take ownership of your ticketing stack. We'll scope it on a call.

Contact