Architecture overview
At a high level, YumKiosk is three components that talk to each other in real time:
[ Kiosk tablet ] [ Agent browser ] [ YumKiosk cloud ]
| | |
| POST /sessions/start | |
|------------------------>| |
| | broadcast incoming |
| |<------------------------|
| | POST /accept |
| |------------------------>|
| video + order state | |
|<===== Agora / WS ======>| |
| | POST /orders |
| |------------------------>|
| session completed | |
|<------------------------| |
The three tiers
The kiosk tier runs on any Android or iPad tablet. It's a web app served from api.yumkiosk.com — no native install, no Play Store submission. The kiosk is identified by a device_id that's generated on first launch and burned into localStorage. Owners pair a new kiosk by entering a 6-digit code on the owner panel, and the tablet trades that code for a long-lived device token.
The agent tier runs at agent.yumkiosk.com. Agents log in with email and password, opt in to "available" status, and start receiving incoming session events over a WebSocket. When they accept a call, the dashboard opens a video feed to the kiosk, shows the live menu, and exposes an order-builder UI. When the order is complete, the agent clicks End session, and the kiosk swaps back to its attract screen.
The cloud tier is a Laravel 12 monolith with a few supporting services. It handles authentication, session routing, order persistence, billing, and real-time fan-out. The cloud is split across multiple subdomains but is really one codebase:
api.yumkiosk.com— public kiosk-facing endpoints (no auth,device_ididentified)agent.yumkiosk.com— agent dashboard + private APIowner.yumkiosk.com— Filament-based owner paneladmin.yumkiosk.com— SuperAdmin panel (impersonation, tenant management)docs.yumkiosk.com— this site
Real-time stack
Real-time messaging goes through Laravel Reverb, which is a first-party WebSocket server that speaks the Pusher protocol. Agents subscribe to a private agent.{id} channel for direct-to-agent events, and to a presence owner.{id} channel that broadcasts kiosk status to the owner dashboard. Kiosks fall back to long-polling via GET /api/public/sessions/{id}/status when a WebSocket isn't available (captive portals, restrictive networks, older hardware).
Video stack
Live video uses Agora. When a session starts, both the kiosk and the accepting agent fetch a signed Agora token from /api/public/agora/token (for the kiosk) or /api/agora/token (for the agent), then join the same channel named after the session UUID. Tokens are short-lived and refreshed automatically if a session runs over an hour.
Payment stack
There are two distinct payment flows:
- Diner → Restaurant: when a kiosk order is placed, it runs through the restaurant's own Stripe Connect account. YumKiosk never touches the money.
- Restaurant → YumKiosk: owners pay YumKiosk a subscription plus hourly agent charges through Stripe Billing on a standard merchant of record setup.
This two-sided split means restaurants keep control of their own processor relationship, while YumKiosk bills them cleanly each month for platform usage.