{"name":"blyp mobile-api","description":"customer-facing rest api for the expo app: better-auth sessions (guest/google/apple), qr-based order claiming, order reads and expo push registration. all /api routes except /api/auth/* require an authenticated customer session (bearer token or cookie).","endpoints":[{"method":"GET","path":"/","description":"this index"},{"method":"GET","path":"/health","description":"readiness probe for Docker/Caddy — 200 with a live DB connection, 503 otherwise. No auth, no detail in the body."},{"method":"*","path":"/api/auth/*","description":"better-auth: sign-in/anonymous (guest), sign-in/social (google/apple via native idToken), get-session, sign-out, update-user (set the customer's display name shown to the merchant)"},{"method":"GET","path":"/api/orders/by-qr/{qrToken}","description":"look up a scanned order without claiming it — backs the app's explicit confirmation screen; returns order number, status, restaurant name/logo/description/type, pickup point name, whether it's already claimed by this customer, and merchantDisabled (informational — claim is what actually enforces it). Note: orderNumber is unique only within the restaurant's current numbering batch, not across its whole history — don't dedupe/cache by (restaurant, orderNumber)"},{"method":"POST","path":"/api/orders/claim","description":"associate the scanned order (body: { qrToken }) with the current customer after the in-app confirmation; idempotent; 409 (code: MERCHANT_DISABLED) when the merchant has been disabled, 409 when the order is no longer active"},{"method":"GET","path":"/api/orders","description":"list the customer's active claimed orders (max 50)"},{"method":"GET","path":"/api/orders/{orderId}","description":"read one claimed order, any status — a push-notification tap resolves here even after the order left the active list (picked up / cancelled). Includes cancellationReason when set by staff; stays readable even if the merchant is later disabled"},{"method":"DELETE","path":"/api/orders/{orderId}/claim","description":"remove the current customer's association with an order (idempotent; also unregisters their push tokens for it) — other customers' claims on the same order are untouched"},{"method":"POST","path":"/api/push/register","description":"register an expo push token for a claimed order (body: { orderId, token }) — used for the 'order ready' notification"},{"method":"DELETE","path":"/api/account","description":"permanently delete the current customer account, its sessions, claims and push tokens"},{"method":"GET","path":"/api/events","description":"server-sent events stream of status changes for the customer's currently claimed orders — event: 'order-status', data: {orderId, status}; event: 'ping' as a ~25s keepalive. Not an oRPC route (plain Hono, see src/sse/route.ts)."},{"method":"GET","path":"/api/files/{key}","description":"streams a restaurant's logo straight from the bucket (the object key returned as organization.logo). No auth — the key itself is unguessable, same posture as the QR token. 404 when object storage isn't configured or the key doesn't resolve. Not an oRPC route (plain Hono, see src/storage.ts)."}]}