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; engagement is ongoing.
How the engagement started
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.
Stage 1 — A custom Laravel platform, multi-organizer from day one
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 / 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 instalment payments
Instalment payments look simple from the outside (split a total into N parts, charge over time). They are not simple 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:
- 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.
- 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.
- 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. This is the same pattern we wrote up in our companion Stripe webhooks reference architecture post.
- 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.
- 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.
Stage 3 — The check-in app for venue staff
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 wasn't 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 single design constraint was speed. When a few thousand people are queued at the door, each check-in has to land in under a second. The decisions that earn that latency:
- 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.
- 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.
- Bluetooth-scanner support for staff who prefer dedicated hardware over the camera.
- Role-scoped login so 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
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 + FCM + APNs post — with the same focus on real delivery measurement rather than ticket-success rates.
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
- 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
| Layer | Stack |
|---|---|
| Web platform | Laravel (PHP) — public booking, organizer back-end, super admin, REST API |
| Frontend (web) | Blade + Vue.js components, hand-audited bundle |
| Database | MySQL with multi-organizer schema, booking + instalment ledger |
| Payments | Stripe — tokenised payment methods, idempotency-keyed charges, webhook-driven reconciliation |
| Scheduled jobs | Laravel queues + scheduler — instalment runs, failed-payment retries, daily Stripe reconciliation |
| Check-in app | React Native (iOS + Android), offline-first scan cache, Bluetooth-scanner support |
| Customer app | React Native (iOS + Android), Expo + FCM + APNs for push, deep links |
| Observability | Structured request logging, Stripe-event ledger, push-delivery instrumentation |
Where it shipped
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.
Engagement is ongoing— day-to-day platform support, new feature work, post-launch observability and payment reconciliation are all owned by us.
■ Related services
Building something in this shape?
The three engagements that map directly to the Ontick rebuild:

About the author
Ritesh — Founding Partner, Appycodes
LinkedInRitesh leads engineering at Appycodes. The Ontick engagement is one of several payments-heavy SaaS builds the team has shipped — others include the BLOC ads + marketplace platform on the same Stripe stack, and the Yippee Malta booking + custom checkout work. Reach out if you have an Eventbrite-style margin problem you want to take ownership of, or a multi-organizer platform that needs a real engineering partner.
