Modify a reservation
const url = 'https://api.useservice.app/v1/reservations/example';const options = { method: 'PATCH', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"party_size":4}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request PATCH \ --url https://api.useservice.app/v1/reservations/example \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "party_size": 4 }'Moves a booking — its day, its time, its party size, the area it sits in, the note the
restaurant reads — and re-checks it against the restaurant’s rules as it goes. Requires
the reservations:write scope.
PATCH is partial. A field you do not send is left alone. A field you send as null
is cleared, which is meaningful for section_id (drop the area preference) and
guest_notes. Sending an empty body is a 400.
The response is the booking as GET /v1/reservations/{id} shows it to your key. On a
booking your key did not make, a key without guests:read does not get guest_notes,
contact_email or contact_phone back, even the guest_notes it just sent.
The booking does not block itself. Capacity, the covers caps and the table search all exclude this reservation, so moving a party of four from 19:00 to 19:30 gives the four covers back at 19:00 before charging them at 19:30, and growing a party from four to six is checked for the two extra covers, not for six.
The table is re-assigned. A modify detaches the booking’s table and picks one again for the new slot, so the party can end up somewhere else even when only the note changed. If no table fits, the whole modify rolls back and the booking is exactly as it was.
The status can move underneath you. A confirmed booking whose new slot or party
size needs the restaurant’s approval comes back pending, and the guest is told their
change has been requested rather than made. Read status from the response.
Approval gates demand from outside the restaurant, so it is the BOOKING’s origin that
decides, not yours: a booking the restaurant made itself (booking_channel of
back_office, walk_in or phone) is already granted and stays confirmed however you
change it. Bookings that arrived through the widget, this API or another channel are
re-checked against the slot.
Refusals are itemised, exactly as on the create. A modify the rules refuse is a 422
with code: "booking_rules_violated" and a violations array, each entry flagged
overridable. Read violations, never the top-level code, which is the same sentence for
one broken rule as for six. Re-send with override set to the codes you accept — the
scope, the 403 with param: "override", the 400 on a code that can never be waived
and the retry-at-most-once rule are all the same as on POST /v1/reservations. Overrides
that actually waived something are recorded on this booking’s change event as
overrides_accepted.
What cannot be changed here. The guest (guest, guest_id), who writes to the guest
(guest_notifications), your metadata and hold_id.
Sending any of them is a 400 naming the field rather than a quiet no-op. So is any field
this operation does not accept at all — internal_notes, table_ids, status — even
beside a field that would apply: nothing is changed. Fields go in the JSON body: one sent
in the query string (?party_size=6) is a 400 naming it too.
guest_notifications in particular is fixed for the life of the booking: a confirmation
that has been sent cannot be unsent, and one that was suppressed cannot be sent late.
Cancel and rebook if you need a different answer.
A change that would RAISE a card guarantee is refused, with 422
guarantee_consent_guest_only. Growing the party on a booking backed by a card imprint
raises the amount the restaurant may later charge, and a higher ceiling needs the
cardholder’s own agreement to the new figure — which is theirs to give and cannot be
given on their behalf, by you or by the restaurant. Nothing is changed; the booking is
exactly as it was. Three ways forward: make a change that does not raise the amount
(moving the time, or shrinking the party, both work and re-price the imprint where
relevant); ask the restaurant to make the change from its back office, which keeps the
existing, lower ceiling; or send the guest to their own booking page, which is the one
place a new amount can be agreed to. Bookings YOUR key created never hit this — their
guarantee is a payment request with an amount the restaurant set, not a guest-consented
imprint — so it is reached only on a booking taken through the restaurant’s own widget.
A change that would put a booking with no card onto a card guarantee is refused, with
422 guarantee_modify_requires_card — growing the party past the size at which the
restaurant asks for a card, or moving onto a service that asks for one for every booking.
A modify cannot collect a card, and nothing is changed. Cancel and rebook: the create
takes the card, or, with the reservations:write:override scope, books without one on
override: ["guarantee_required"]. This code is never overridable on the modify itself.
A booking whose current slot and party already call for a guarantee it does not have is
not refused by this rule, and neither is one at a restaurant that cannot take card
payments right now.
excluded_from_shift_limits can be corrected here, and setting it to true requires the
reservations:write:override scope exactly as it does on the create. Setting it
to false — giving the exemption up — requires nothing.
A booking that is completed, no_show or cancelled is a 409 reservation_finalized.
Holds are not reachable here. A hold_… id is not a reservation id, and a held slot
is not served by this collection at all — release it with DELETE /v1/holds/{id} and take
another.
Idempotency-Key is OPTIONAL on this endpoint, unlike on POST /v1/reservations and
POST /v1/holds. Applying the same change twice is ordinarily harmless — the second pass
finds nothing to change and writes nothing. The one thing a key buys you is the table:
because every modify re-runs the table search, a blind retry can seat the party somewhere
else and email the guest about a change they did not make. Send a key if you retry
automatically. When you do, the original response is replayed verbatim, so it shows the
booking as it was at the first attempt.
Writes have their own rate budget, lower than the read one, shared with every other write on
this restaurant. See POST /v1/reservations.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Reservation id (resv_…)
Header Parameters
Section titled “Header Parameters”Optional. Re-send the same value to retry a modify safely. At most 255 characters, and no control characters: a longer or unprintable key is a 400 idempotency_key_invalid``, not a silently truncated one. Keys are scoped to your restaurant — another restaurant’s key of the same value is a different key — and are remembered for 72 hours, after which the same value starts a new request.
Pin this request to a dated version of the contract, e.g. 2026-09-01. Omit it and the version pinned on the API key applies. A version we do not publish is a 400 bad_request with param: "Service-Version". The version that was applied comes back on the Service-Version response header, always.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The service day the booking belongs to, YYYY-MM-DD in the restaurant’s timezone. A seating after midnight in a service that began the evening before keeps that evening’s date, so it can differ from the date in starts_at.
HH:MM on the restaurant’s clock: a slot time GET /v1/availability offered for this service_date.
How many guests the booking is for.
Seat in one area (sec_…). null clears the preference.
What the guest asked for, in their own words. The restaurant sees it on the booking. Reading it back follows the response’s guest_notes.
The restaurant’s own note about this booking, as its staff would type it into the reservation form. Never shown to the guest. Reading it back follows the response’s internal_notes, which needs guests:read — on this booking as on any other.
File the booking under one of the restaurant’s companies (cmp_…), as its own staff would — the id is the one company.id carries on a booking already filed under it. null files it under no company. An id this restaurant does not know is a 404 naming company_id.
Booking rules you accept breaking, for this change only. Requires the
reservations:write:override scope. Each value names a rule, and sending it waives that
rule whether or not the refusal reported it — so you can send one ahead of the round trip.
guarantee_required is the rule “this slot asks the guest for a card”. You are only
REFUSED with it when the card cannot be asked for — no address the pay-link can reach —
but waiving it always means the same thing: the booking is made with no card guarantee at
all, and the guest is never asked for one.
Correct whether this booking is charged to the shift’s covers caps. Setting it to true requires the reservations:write:override scope; setting it to false requires none.
Ask the guest for a card now. The booking goes back to awaiting_guarantee and is confirmed again when the card is saved. Only on a confirmed, upcoming booking that carries no guarantee yet — anything else is a 422 guarantee_request_not_allowed.
We e-mail the guest a payment link. Send {} to ask on the restaurant’s own terms, or set
any of the three below. Needs no scope beyond reservations:write, and needs a guest
e-mail address — without one the request is a 422 email_required_for_guarantee.
Not the same thing as the slot’s own guarantee, which applies whether or not you send this
and is described by guarantee on GET /v1/availability. Sending this on such a slot
replaces the amount and deadline it would have used.
A restaurant that cannot take card payments refuses the request with 422 payments_suspended, unlike a booking on a guaranteed slot, which is simply confirmed
without a card.
object
How much to guarantee, in the restaurant’s currency’s smallest unit, for the whole party. Omit it for the amount the slot’s own guarantee policy would have used. Must be greater than zero; a slot with no policy and no amount here is a 422 guarantee_amount_invalid.
How long the guest has to save the card. Defaults to 48. Clamped, never refused: a deadline past the booked time — or past free cancellation, when that comes sooner — is brought forward, and the guarantee.expires_at on the response is the one that applies.
Cancel the booking when the deadline passes with no card saved. Defaults to true. Set it to false to keep the booking and let the restaurant decide.
Example
{ "party_size": 4}Responses
Section titled “Responses”Reservation modified
object
The object type: always reservation.
The booking’s id, resv_…. Opaque and permanent. A booking converted from a hold keeps that hold’s suffix: hold_AbC becomes resv_AbC.
Where the booking is in its lifecycle.
⚠️ held and awaiting_guest never appear on a reservation this API serves — a
hold is its own object (GET /v1/holds) and a waitlist promotion awaiting its guest
is not yet a booking — so no endpoint, and no reservation.* webhook, can carry
either value. They are listed because the enum is the platform’s own and codegen
reads it verbatim. awaiting_guarantee DOES appear: it is a booking waiting for the
guest to save a card.
There is no late. The restaurant’s screens show a party as late from its start
time, but that is worked out on the spot and never stored, so a late party keeps the
status it had, usually confirmed.
The mechanism that created the booking. See booking_channel for the channel the
demand arrived through — a waitlist booking promoted by staff still has the channel
the guest joined through.
manual: entered by the restaurant’s staff.widget: made by the guest in the restaurant’s booking widget, including a widget embedded on a partner’s page.walk_in: a party seated without a booking.import: brought over from the restaurant’s previous reservation system.waitlist: came out of the waitlist.api: created through this API (POST /v1/reservations).
The channel the demand arrived through, as opposed to source, the mechanism.
back_office: taken by the restaurant’s staff.website_widget: the restaurant’s own booking widget.phone: taken by telephone.walk_in: a party that walked in.google_reserve: booked through Google.partner_platform: taken in the booking widget embedded on a partner’s own page.api: created through this API (POST /v1/reservations), including a hold converted into a booking.
How many guests the booking is for.
The service day the booking belongs to, YYYY-MM-DD in the restaurant’s timezone. A seating after midnight in a service that began the evening before keeps that evening’s date, so it can differ from the date in starts_at.
When the party is due to sit down: ISO 8601 with the restaurant’s UTC offset, e.g. 2026-07-01T20:00:00+02:00.
When the table is expected back, in the same format as starts_at. null when no seating duration applies to the booking.
What the guest asked for, in their own words. Guest data: present only when your key
carries guests:read — on every booking alike, including the ones your key made.
Otherwise the field is absent, not null. Every webhook delivery carries it.
Who writes to the guest about this booking. partner_managed means we send none of the discretionary guest messages for it. Treat the list as open.
True when this booking does not count against the shift’s covers caps — a private event seated apart from the room those caps describe.
Those caps do not refuse it either, so a party larger than the covers left is booked rather than turned away. It still holds its table, and it still appears in every count of guests.
Setting it requires the reservations:write:override scope, except on a
whole-section booking (entire_section_id), where it is the default.
The e-mail address this booking’s messages go to, as given when it was made. null
means the booking uses the guest profile’s address. Guest data: present only when
your key carries guests:read — on every booking alike, including the ones your key
made. Otherwise the field is absent, not null. Every webhook delivery carries it.
The phone number this booking’s messages go to, as given when it was made. null
means the booking uses the guest profile’s number. Present on the same terms as
contact_email.
The restaurant’s own note about this booking — what its staff would type into the reservation form. Not shown to the guest anywhere.
Guest data, and gated exactly like guest_notes: present only when your key carries
guests:read — on every booking alike, including the ones your key made. Otherwise
the field is absent, not null. Every webhook delivery carries it.
The guest’s id, gst_… — the unexpanded form.
A guest profile from the restaurant’s guest book. Guest data: served by GET /v1/guests and ?expand=guest, both of which need the guests:read scope, and carried by every guest.* webhook delivery.
object
The object type: always guest.
The guest’s id, gst_…. Opaque and permanent. When two profiles are merged, the one that disappears keeps resolving to the survivor in ?id= on GET /v1/guests.
First name. A profile has a first name or a last name, possibly both; null when it has only the other.
Last name. null when the profile has only a first name.
Primary e-mail address, trimmed and lower-cased. null when none is known.
Primary phone number: E.164 (+33612345678) when it could be parsed for the restaurant’s country, otherwise as entered with separators removed — so do not assume E.164. null when none is known.
The restaurant’s own notes on the guest profile: free text written by its staff, or carried over from its previous reservation system — the restaurant’s words about the guest, not the guest’s. A booking’s guest_notes are the guest’s own. null when there are none.
Whether the restaurant has flagged this guest as unwelcome. A flag only: it does not by itself refuse a booking.
Why the guest was flagged — required by the restaurant when it sets blacklisted. null when the guest is not flagged.
Dietary preferences the restaurant recorded, as free-form labels. [] when none.
Allergies the restaurant recorded, as free-form labels. [] when none.
Date of birth, YYYY-MM-DD. null when not recorded.
An anniversary date the restaurant recorded, YYYY-MM-DD. null when not recorded.
Whether the restaurant marked the guest as a VIP.
The language the restaurant writes to this guest in, as an ISO 639-1 code. Set to the restaurant’s primary language when the profile is created unless one is given, so null only on a profile that never had one.
How the restaurant first learned of this guest. Not the same vocabulary as a
reservation’s source.
manual: entered by the restaurant’s staff.widget: first seen booking in the restaurant’s booking widget.import: brought over from the restaurant’s previous reservation system.host_assertion: first seen booking through the widget embedded on a partner’s page, with the partner vouching for their identity.api: first seen on a booking created through this API.website_newsletter: first seen signing up to the newsletter on the restaurant’s website.
Whether the guest agreed to receive marketing e-mail from the restaurant.
When marketing_email_consent last became true, ISO 8601 with the restaurant’s UTC offset. null while consent is false.
Whether the guest agreed to receive marketing text messages from the restaurant.
When marketing_sms_consent last became true, ISO 8601 with the restaurant’s UTC offset. null while consent is false.
How many of the guest’s bookings ended with them seated (seated, partially_seated or completed). Recomputed hourly, so it can trail a visit by up to about two hours.
How many of the guest’s bookings ended no_show. Recomputed like visit_count.
How many of the guest’s bookings were cancelled, counting only bookings whose time has passed — a cancelled booking for next month is not counted until then. Recomputed like visit_count.
When the guest’s earliest visit (a booking counted in visit_count) started: ISO 8601 with the restaurant’s UTC offset, on the calendar day it actually started — a seating after midnight carries the next day’s date. null until they have one. Recomputed like visit_count.
When the guest’s latest visit started, in the same format as first_visit_at. null until they have one. Recomputed like visit_count.
When the profile was created: ISO 8601 with the restaurant’s UTC offset.
When the profile last changed, in the same format. The value updated_since compares against.
The company the booking is made for, when it was filed under one — by the restaurant’s staff, or by company_id on your own create or PATCH. null otherwise, which is the common case; the key is always present. Readable by every key with reservations:read, unlike the guest’s own details.
object
The object type: always company.
The company’s id, cmp_….
The company’s name, as the restaurant recorded it.
The tables the booking is seated at, each with its seating area. [] while no table is assigned.
object
The object type: always table.
The table’s id, tbl_…. Opaque and stable.
The table’s name on the restaurant’s floor plan.
The smallest party the table is meant for. Always a number, never null.
The largest party the table seats on its own — a larger party needs tables joined together. Always a number, never null, and never below min_capacity.
The seating area the table is in.
object
The object type: always section.
Pass this as section_id to GET /v1/availability or to a create — any member of a group resolves to the whole group, so a sec_… read off a reservation’s table works without knowing which row it is.
The area’s name, in the restaurant’s primary_language.
The kind of space, as the restaurant classified it: indoor, outdoor, terrace,
bar, lounge, private_room (a room of its own), patio or rooftop. For a group,
take it from the row where group_id == id.
Whether THIS row is offered for online booking. Per row, never per group: it is deliberately not cascaded between group members, so a group is worth offering when ANY of its rows is true.
The sec_… id that identifies the conceptual seating area this row belongs to.
Rows sharing a group_id are ONE choice to a guest — the same area drawn on more than
one floor plan — so group by it before rendering a picker, or the same area is offered
twice.
Exactly one row per group has group_id == id: take that row’s name and
area_type as the group’s. The others are kept in step by the product and are
normally identical, but that is a behaviour of its editing paths rather than a
constraint, so the naming row is the answer that cannot go stale.
The card guarantee attached to the booking. null when it has none. Always included; no scope or expand needed.
object
The object type: always guarantee.
What the guest is guaranteeing with.
imprint: a saved card, charged only on a no-show or a late cancellation.prepayment: payment up front. Reserved: no guarantee is issued with it today.
Where the guarantee is in its own lifecycle, which is separate from the booking’s
status.
awaiting_card: waiting for the guest to save a card, untilexpires_at.active: a card is saved and can be charged under the terms the guest accepted.expired: the guest did not save a card in time.withdrawn: the restaurant withdrew the request before a card was saved.released: the card was let go and nothing will be charged.charged: the fullamountwas charged.partially_charged: less thanamountwas charged.charge_failed: a charge was attempted and declined; it may be retried.refunded: money charged was refunded in full.disputed: the guest disputed the charge with their bank.
How the card was asked for.
online_booking: the guest saved it while booking in the restaurant’s widget.staff_request: the guest was sent a link to save it — by the restaurant, or because the booking was created through this API.waitlist_offer: the guest saves it to claim a place offered from the waitlist.
The most that can be charged, as the guest accepted it: in the minor unit of currency (cents), so 4000 is €40.00. Covers the whole party.
ISO 4217 currency code of every amount on this object, e.g. EUR.
How much has been charged so far, in minor units of currency. 0 when nothing has.
How much of charged_amount has been refunded, in minor units of currency. 0 when nothing has.
null until the guest saves a card, and on a guarantee that never had one. Once a card is saved, its brand and the last four digits of its number; last4 can be null when the card network does not report it.
object
The card network, as the payment processor reports it, e.g. visa.
The last four digits of the card number.
Until when the guest can cancel without being charged: ISO 8601 with the restaurant’s UTC offset. A cancellation after it may be charged. null means cancelling is always free and only a no-show is charged.
While state is awaiting_card, the deadline for the guest to save a card, in the same format. null in every other state.
When the terms the guest accepts were recorded, in the same format: when the card was saved in the booking widget, or when the request was sent for a card asked for by link. null on a widget booking whose card is not saved yet.
When the guarantee was created, in the same format.
When the guarantee last changed, in the same format.
Your own reconciliation data, echoed verbatim on every read and webhook; {} when
there is none.
Set once, when the booking is made, and never changed afterwards — PATCH refuses
it. It comes from metadata on POST /v1/reservations, or from the hold the
booking was converted from. A booking made in the restaurant’s own widget carries
metadata only when the widget was embedded by a partner platform that signed it into
its identity assertion; an unsigned widget booking never has any.
⚠️ Readable by every integration this restaurant has authorised, not only by the one that wrote it. Put reconciliation ids here, not commercial terms.
object
The booking’s lifecycle events, oldest first — the same list GET /v1/reservations/{id}/events returns. Present only when you pass ?expand=events on a read, which needs no scope beyond reservations:read; absent otherwise, never an empty stand-in.
object
The object type: always reservation_event.
The event’s id, evt_…. Opaque and permanent. Not the id of the webhook event that announced the same change: the two are numbered separately.
What happened, named like the webhook event for the same change.
reservation.created: the booking was made.reservation.pending: it became a request awaiting the restaurant’s decision.reservation.confirmed: the restaurant accepted it.reservation.declined: the restaurant turned the request down.reservation.updated: its details or its tables changed.reservation.partially_seated: part of the party was seated.reservation.seated: the party was seated.reservation.completed: the party left.reservation.cancelled: it was cancelled —data.cancellation_reasonsays how.reservation.no_show: the party did not come.
When it happened: ISO 8601 with the restaurant’s UTC offset.
What changed, keyed per event type — statuses as from_status/to_status, field
edits under changes. Internal ids, staff identity and the staff’s own notes are
stripped. Treat the key set as open.
Six keys carry the guest’s own data and appear only when your key could read that
field on the booking — that is, when it carries guests:read:
contact_email,contact_phone,guest_notes— the booking’s own contact details and the note the guest left, insidechangeswhen one of them is edited.submitted_guest_name,submitted_email,submitted_phone— on thereservation.createdevent, what the booker actually typed, recorded when it differs from the guest profile the booking was matched to.
On reservation.cancelled, cancellation_reason says who ended the booking and how:
partner_apiis a cancel YOU made throughPOST /v1/reservations/{id}/cancel.guest_self_serviceis the guest cancelling from their own manage link.guarantee_expiredis a card request that lapsed unpaid.
Anything else was typed by the restaurant; match on the three named values and pass the rest through.
object
The guest’s own credential for their booking page. That page is on the booking host
that public_booking_url in GET /v1/configuration names, not on this API, and the
link is {public_booking_url}/{modification_token}, the same link the confirmation
e-mail sends the guest.
Whoever holds it can do on that page everything the guest can: read, change or
cancel the booking and, while it is awaiting_guarantee, complete the card step.
Pass it only to the guest, as the link to their own page; never log it, display it
or keep it longer than you need it. The endpoints behind that page are the booking
widget’s, not part of this API.
⚠️ Present ONLY on the POST /v1/reservations response, and only when you ask with
?expand=modification_token and your key carries guests:read (it reads the
guest’s contact details, so it is gated like the guest book). Reads, lists and
webhooks never carry it — capture it at create time. Never null when present.
How long it lasts. It is minted once, when the booking is created, and never
rotates: the value you capture is the value that booking keeps. It carries no
expiry of its own and stays usable for as long as the booking is live, which in
practice means until the party has been and gone. Cancelling — by you, by the
guest or by a card request lapsing — retires it, and so does the restaurant
marking the booking a no-show: the page answers 404 from then on, exactly as it
does for a token that was never issued. There is no way to
revoke it while the booking stands, which is the other half of “never log it”:
if it leaks, the remedy is to cancel and rebook.
When the booking was recorded: ISO 8601 with the restaurant’s UTC offset.
When anything on the booking last changed, in the same format. The value updated_since compares against.
Example
{ "object": "reservation", "status": "awaiting_guarantee", "source": "manual", "booking_channel": "back_office", "guest_notifications": "service_managed", "guest": { "object": "guest", "language": "fr", "source": "manual" }, "company": { "object": "company" }, "tables": [ { "object": "table", "section": { "object": "section", "area_type": "indoor" } } ], "guarantee": { "object": "guarantee", "kind": "imprint", "state": "awaiting_card", "origin": "online_booking" }, "events": [ { "object": "reservation_event", "type": "reservation.created" } ]}Headers
Section titled “Headers”Dated API version applied
Present, as true, only when this response replays an earlier request with the same Idempotency-Key; the body is that original response, verbatim. Absent on a first write.
Nothing to modify, or a field that cannot be changed
The envelope every public-API error answers with, whatever the status.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Example
{ "error": { "type": "invalid_request_error" }}No API key, or not a live one
The envelope every public-API error answers with, whatever the status.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Example
{ "error": { "type": "invalid_request_error" }}Headers
Section titled “Headers”Unique id for this request. Quote it to support: it is how a specific call is found in our logs. Generated per request, or echoed from the X-Request-Id you sent.
The API key does not carry the reservations:write scope
The envelope every public-API error answers with, whatever the status.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Example
{ "error": { "type": "invalid_request_error" }}Headers
Section titled “Headers”Unique id for this request. Quote it to support: it is how a specific call is found in our logs. Generated per request, or echoed from the X-Request-Id you sent.
No such reservation
The envelope every public-API error answers with, whatever the status.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Example
{ "error": { "type": "invalid_request_error" }}Headers
Section titled “Headers”Unique id for this request. Quote it to support: it is how a specific call is found in our logs. Generated per request, or echoed from the X-Request-Id you sent.
The booking is finalized
The envelope every public-API error answers with, whatever the status.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Example
{ "error": { "type": "invalid_request_error" }}The change breaks the restaurant’s booking rules
The 422 a write answers with when it broke the restaurant’s booking rules: the envelope above plus the itemised violations. No other status carries that array.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Every booking rule this request broke, itemised. The whole array is the refusal: the top-level code is the fixed umbrella booking_rules_violated and the top-level message one fixed sentence, for one broken rule as for six. Only a 422 carries it.
object
The rule that was broken, e.g. cutoff_passed.
A human-readable explanation of this violation.
The request field to change to satisfy the rule, when there is one. Absent — not null — otherwise.
Whether a key carrying reservations:write:override may re-submit with this code in override and have the rule waived.
Only on section_occupied: what already holds part of the room during the window — one entry per occupied table, with the time it is held from and to. Never who holds it. Absent on every other code.
object
The occupied table (tbl_…). Null when the room has no tables and another whole-room booking holds it.
When the table is held from: HH:MM on the service_date the request named, in the restaurant’s timezone. Read on the service’s own axis, which runs past midnight — a 00:30 against a 23:30 is half an hour later the same night, not 23 hours earlier.
When the table is held until, on the same clock and the same axis as start_time. null for a booking stored without an end time.
The envelope every public-API error answers with, whatever the status.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Example
{ "error": { "type": "invalid_request_error" }}Too many requests on the write budget
The envelope every public-API error answers with, whatever the status.
object
Every error response carries this one object.
object
The broad class of the error, from the HTTP status.
invalid_request_error: a400,403,404,409or422— something about the request to change.authentication_error: a401— the key is missing, invalid, revoked or expired.rate_limit_error: a429— slow down and retry.api_error: any other status, a fault on our side.
The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.
A human-readable explanation for the developer. Its wording can change.
The request parameter the error is about, when there is one — e.g. expand or limit. Absent — not null — when the error names no field.
A link to this code in the errors reference. Always present.
Example
{ "error": { "type": "invalid_request_error" }}Headers
Section titled “Headers”Requests permitted in the write burst
Requests remaining in the write burst
Seconds until the write bucket refills
Which budget the numbers describe. write here.
Seconds to wait before retrying
Unique id for this request. Quote it to support: it is how a specific call is found in our logs. Generated per request, or echoed from the X-Request-Id you sent.