Text a "waiting now" guest that their table is ready
/api/waitlist/{id}/table-readyThe 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.
Authorization
sessionCookie 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
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/table-ready"{ "ok": true}Offer a waitlisted guest a table POST
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.
Close out a waitlist entry PATCH
Sets `status` to `converted`, `expired` or `cancelled`. **`notified` is deliberately NOT settable here**, and it is the only interesting rule on this route. That status is a claim about a message that left the building; setting it from a plain PATCH would let the list show an offer that was never sent, with the guest waiting at home for an email nobody dispatched. Only POST ./offer writes it, after the send. The three end states are terminal; a `converted` entry cannot be dragged back to `open` and offered again to a guest who is already booked. No minRole: clearing a waitlist is ordinary floor work.