Skip to content

Change a held time

You are holding 20:00 for a party of four and the guest now wants 21:00. The API has no call that moves a hold: /v1/holds offers create, read and release, nothing that edits the time, the date, the party size or the section, and a conversion that names a different slot from its hold is refused. To change the time you take a new hold, then release the old one — a swap — with availability reads between the two.

This comes up most in a package funnel that takes its hold early, while the basket is still being assembled, and then lets the guest change their mind. Taking and releasing a hold is covered in Hold a slot.

Read availability with your own hold excluded

Section titled “Read availability with your own hold excluded”

A hold occupies its table for the whole booking duration, so every overlapping slot loses it, and its covers count against the shift cap. A funnel holding 20:00 that then asks what else is free is reading a day with 20:00 missing from it, and if the hold took the last table for that party size the guest is being shown their own held time as unavailable.

excluding answers as if the hold were not there:

Terminal window
curl -G "https://api.useservice.app/v1/availability" \
-H "Authorization: Bearer $SERVICE_API_KEY" \
-d service_date=2026-10-04 \
-d party_size=4 \
-d excluding=hold_AbC3xK9

It takes a hold_… id or the resv_… id of a booking, and only ids your key could already fetch: a value that does not resolve on GET /v1/holds/{id} or GET /v1/reservations/{id} is a 404, and a value that is neither shape is a 400 naming excluding. It varies the ETag, so a funnel that revalidates gets the excluded body rather than the one it already had.

GET /v1/availability/months takes it too. The calendar grain is coarser, but in a small dining room one hold is enough to empty a day — and a calendar that greys out the date the guest is holding leaves them nowhere to go, because it sits upstream of the day view they would have used to get back.

Take the new hold before you release the old one

Section titled “Take the new hold before you release the old one”

Release-then-create opens a window in which the table is on sale and somebody else can take it. Create-then-release opens none: you hold two tables for one round trip and drop the loser.

  1. POST /v1/holds for the new time, taken from the availability read. A time the service does not seat at is refused with start_time_off_grid, and you are still holding the original.
  2. On success, DELETE /v1/holds/{old_id}.
  3. On failure, you are still holding the original. Tell the guest that time has just gone and leave them on the one they have. The one exception: a hold.released you did not cause means the restaurant released the original from its back office, and then there is nothing left to leave them on.

Writes are limited to one per second, burst 20, and 2,000 a day — see Rate limits. A guest toggling between six times is twelve writes for one booking, and a Saturday of that reaches the daily cap on its own. Hold when the guest commits — on “continue”, not on selection — and serve everything before that from availability reads with excluding.

The swaps show up in your webhooks as churn

Section titled “The swaps show up in your webhooks as churn”

Every swap emits a hold.created and a hold.released. A consumer syncing off those sees six holds and five releases for a party that booked once, so reconcile against the reservation rather than against the hold feed.

It protects the time you suggested, if the guest takes it. The moment they move, the hold bought nothing for the time they picked: that table was never held, and the new hold can fail like any other write.