Keys Please Valet API

v1.0 · Express + JWT · matches platform spec

Auth

POST /auth/login public — staff login, returns JWT
GET /auth/me jwt — current user

Tickets (Staff)

GET /tickets?status=requested jwt — list active tickets
POST /tickets jwt — create check-in
POST /tickets/:id/video/sign jwt — phase 1: Cloudinary signed upload preset
POST /tickets/:id/video jwt — phase 2: confirm walk-around video uploaded
POST /tickets/:id/park jwt — assign stall & park (requires video)
POST /tickets/:id/complete-retrieval jwt — mark delivered
GET /tickets/:id/timeline jwt — full event log

Parking

GET /parking/map jwt — full stall layout
GET /parking/occupancy jwt — live occupancy stats

Reports (Manager / Operator)

GET /reports/summary?days=7 mgr/op — KPIs + deltas
GET /reports/revenue?days=7 mgr/op — daily revenue timeseries
GET /reports/hourly?days=14 mgr/op — hour-of-day check-in heatmap
GET /reports/staff?days=7 mgr/op — attendant leaderboard
GET /reports/activity?limit=30 mgr/op — recent events feed
GET /reports/videos?limit=50 mgr/op — uploaded walk-around audit
GET /reports/venues?days=7 operator — per-venue rollup for switcher

Public (Guest PWA)

GET /public/venue?org_id=… org_id — venue info from QR
POST /public/tickets org_id — guest self check-in
GET /public/tickets/:token org_id — poll ticket status
GET /public/tickets/:token/timeline org_id — guest timeline
POST /public/tickets/:token/request-retrieval org_id — "Request My Car"
GET /public/tickets/:token/quote org_id — current fare
POST /public/tickets/:token/pay org_id — settle & pay

Platform (Network-wide)

GET /platform/operators?days=30 platform — list operators with rollup
GET /platform/operators/:id platform — single operator detail
GET /platform/summary?days=30 platform — network totals
GET /platform/activity?limit=40 platform — network event stream
POST /platform/onboard platform — create operator + first venue + first manager

Incidents (Damage / Theft / Disputes)

GET /incidents?status=open&severity=damage mgr/op — list with filters
GET /incidents/:id mgr/op — single incident detail
POST /incidents jwt — flag from a ticket
POST /incidents/:id/review mgr/op — begin investigation
POST /incidents/:id/resolve mgr/op — close with outcome
GET /incidents/ticket/:ticket_id jwt — all incidents on a ticket

Health

GET /health public
GET /realtime/stats public — active socket count

Realtime (WebSocket)

WS /realtime?token=<jwt> jwt — staff/manager event stream
WS /realtime?org_id=<id>&ticket_token=<n> org_id — guest event stream (per ticket)
Demo creds (password "demo" for all — stored as bcrypt hashes)
Platform admin: morgan@keysplease.dev — entire network (both operators)
SF Operator: alex@keysplease.dev — 3 SF venues
LA Operator: sasha@keysplease.dev — 3 LA venues
Venue Manager: dani@keysplease.dev (Sable), devon@keysplease.dev (Chateau)
Attendants: mauricio@, priya@, omar@, jin@, carlos@, mia@, tomas@, rachel@