Hospitality engine

Offer a waitlisted guest a table

post/api/waitlist/{id}/offer

The staff-triggered half of the waitlist, in one button. Emails (and texts, if the guest left an E.164 number and the org has SMS on) a link back into the booking flow prefilled with the date and party size, then sets the entry to notified with notifiedAt.

Send first, mark second, deliberately. Marking first would be the tidier transaction, but notified would then be a lie whenever the mail provider is down: the list would show the guest as offered, nobody would offer them again, and the table would go empty. Failing the other way produces at worst a duplicate "a table has come free" for a table that is in fact still free.

Every attempt is recorded in book_notification_log against waitlistEntryId with type waitlist_offer; the third subject 0044 added to that table. There is no dedupe index on this subject, so re-offering is legal and expected: the 7pm cancellation the guest did not answer is followed by an 8:30 one an hour later.

v1 is staff-triggered and there is no auto-broadcast. "First to reply Y wins" needs inbound SMS, which does not exist anywhere in this codebase.

Authorization

sessionCookie
sb-qxrvgfkjyvbngipqvslu-auth-token<token>

The dashboard's Supabase Auth session cookie, set at sign-in. Large sessions are split across numbered chunks (…auth-token.0, .1), so treat this as a cookie family rather than one name.

Every request re-validates it against the Auth server (getUser()), never by decoding the cookie locally: a JWT nothing has checked is not a credential. Tenancy is then read from the verified app_metadata.company_id claim and enforced by row-level security; it is never read from request input, on any route, ever.

role (admin / staff) is deliberately not in RLS. It gates specific actions in route code, the operations marked admin below, so hiding a button in the UI is cosmetic only, and a route's own check is the enforcement.

In: cookie

Path Parameters

id*string

Waitlist entry id.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/api/waitlist/string/offer"
{  "ok": true,  "email": "sent",  "sms": "sent"}

Add a party waiting now at the door POST

The `source: 'staff'` half of the unified Waitlist (migration 0232): a host taking a name and a number at the door, the retired walk-in queue's own job folded into this one table. Any member, not admin-only: taking a name at the door is the job of whoever is on the door. **A phone number is REQUIRED**, unlike a `source: 'online'` entry where an email carries the offer. The entire value here is the guest being somewhere else when the table frees, so an entry that cannot be texted is a person standing at the host stand, which is what this removes. The number is NOT required to be E.164: `toE164` resolves whatever the host typed against the company's own country and timezone at send time, so "0412 345 678" works. `requestedDate` is always the venue's own local today: there is no date picker at the door, only "now" (`book_waitlist_entries_staff_shape`). There is deliberately **no public route** onto this half. A guest joins by standing in front of a host who reads the room and quotes a wait; a public one would let anyone put any number in any venue's queue from anywhere, and the venue would then text them.

Text a "waiting now" guest that their table is ready POST

The `source: 'staff'` mirror of POST .../offer: the same member-scoped tenant check, refusal shape and send-then-mark ordering, but texts via SMS rather than mailing, since a `source: 'staff'` entry carries a phone and commonly no email at all. Refuses a `source: 'online'` entry (409): it has no guaranteed phone number, and "your table is ready" makes no sense for a future date nobody has actually booked yet. **Send first, mark second**, deliberately: marking first would make `notified` a lie whenever the SMS provider is down. Logged into `book_notification_log` against `waitlistEntryId` with type `table_ready`.