Request-approval bookings
How request-mode services work: the 24-hour decision window, approvals and declines, deadline expiry and what the guest is told.
Not every service has to confirm instantly. A venue can set a service’s approval mode to Request, and every booking on that service then becomes a request the venue decides by hand. The guest experience, the decision window, the approval checks and the expiry rule are all fixed by the system — this page describes exactly what happens at each step. Booking itself works identically to an instant service, so read Making a booking first if you have not seen the form.
When a booking becomes a request
Managers choose the approval mode per service when they configure offerings — see Offerings & schedules. On a request-mode service the submit answers with the heading “Request sent” and the line “Request sent — the venue will confirm by email.”
A request holds no table. The record is created in the REQUESTED state
without an allocation, so the venue’s inventory stays open to other parties
until the request is approved. That is deliberate, and it is why an approval
can still lose the slot (see below).
A request-mode service cannot also require a deposit: the combination of
REQUEST approval and deposit terms refuses with PAID_BOOKING_UNAVAILABLE
during the pilot, on the guest path and on the staff path alike.
The decision window
The deadline is the earlier of two instants: 24 hours from submission, or the service start. The system records which one bound the outcome, and staff forms report it as “review requested until {timestamp}”. A request that arrives less than 24 hours before the table therefore gets a shorter window — it can never be decided after the party was supposed to arrive.
Deciding a request
Pending requests appear with the REQUESTED status on the venue’s Today
board. The approve/decline command itself currently runs from the
Request decisions form on the operator panel — a dedicated
decision screen is on the roadmap, and the panel runs the same server
command that screen will call. Deciding requests is a manager-and-up act
(reservations.approve): owners, organization admins and managers decide;
hosts and door staff do not, and the server re-verifies the role on every
call no matter which surface is used.
| Decision | What the server does |
|---|---|
| Approve | re-runs the full availability check for the exact slot against the current service state, allocates the tables, and flips the record to CONFIRMED |
| Decline | records the reviewer’s reason and flips the record to DECLINED |
An approval can honestly fail. If the slot sold out while the request was
pending, the command answers SLOT_UNAVAILABLE with the nearest open times
attached, and the request stays pending — the right move then is to decline
with a reason rather than approve into a sold table. If the accepted terms
carry a deposit, approval refuses with PAID_BOOKING_UNAVAILABLE; only free
requests confirm during the pilot. Deciding against a stale read answers
RESERVATION_STALE — reload the row’s version and retry — and deciding an
already-decided request answers RESERVATION_STATE_CONFLICT, because exactly
one decision per version ever lands.
Declines and the reason
A decline requires a reason. It is written onto the reservation record and into the audit trail with the reviewer’s identity and timestamp. The guest learns the outcome by email (“Your booking request was declined — {venue}”, with the confirmation code) and on their self-service page, whose status headline changes to “Declined by the venue”. The guest-facing pages in this pilot show the decision itself; the written reason stays on the venue’s record for the team.
Deadline expiry
Undecided requests are expired by an explicit sweep: every REQUESTED row
whose deadline has passed flips to EXPIRED with a recorded reason —
REVIEW_DEADLINE when the 24-hour window bound the outcome first,
SERVICE_START when the service start did. Replaying the sweep expires
nothing twice. The background worker owns the schedule; a manager can also
run the “Expire overdue requests” sweep by hand for one venue at any moment,
and an empty sweep is a normal answer.
What the guest is told at each step
| Step | Confirmation screen | Self-service status | |
|---|---|---|---|
| Submitted | “Request sent — the venue will confirm by email.” | “We received your booking request — {venue}”, stating plainly: “This is a request, not a confirmation; we will email you the decision.” | “Waiting for the venue to confirm” |
| Approved | — | “Your booking at {venue} is confirmed” with the code, date and time, party size and amount due at the venue | “Confirmed” |
| Declined | — | “Your booking request was declined — {venue}” with the confirmation code | “Declined by the venue” |
| Expired | — | “Your booking request expired — {venue}” plus “You are welcome to request another time.” | “Expired” |
During the unpaid pilot no email provider is connected, so these emails are composed and then recorded as visible failed deliveries rather than sent. The venue’s decision is still authoritative in the system: staff see it on the board, and a guest holding a
/blink sees the status change there — see Guest self-service links.
What a guest can do while a request is pending
Guests have no approve/decline power — the decision belongs to the venue. A
guest who holds a self-service link can cancel a pending request themselves
(CONFIRMED and REQUESTED are the two cancellable states); there is no
guest reschedule in the pilot, so changing plans means cancelling and
booking again — see Changing & cancelling.
Errors you may see
| Code | Meaning | What to do |
|---|---|---|
PERMISSION_DENIED |
your role cannot decide requests (host, door, finance, read-only) | ask a manager, org admin or owner to decide |
RESERVATION_STALE |
the request changed since you read it | reload the row and redo the decision against the current version |
RESERVATION_STATE_CONFLICT |
the request is not pending any more | reload — it was already approved, declined or expired |
SLOT_UNAVAILABLE |
the slot sold out before approval | decline with a reason; the nearest open times are attached for a fresh booking |
PAID_BOOKING_UNAVAILABLE |
the accepted terms require a deposit | decline with a reason; paid approvals stay closed during the pilot |
POLICY_STALE |
the terms changed between acceptance and decision | review the current policy, then decide |
VENUE_LOCK_TIMEOUT |
the venue was too busy to commit | retry the same decision |
Every code with its remedy is listed in Error codes & fixes; the email texts that carry these outcomes are described in Messages, confirmations & reminders.