Aller au contenu

The restaurant's booking policy

GET
/v1/configuration
curl --request GET \
--url https://api.useservice.app/v1/configuration \
--header 'Authorization: Bearer <token>'

What a booking funnel reads once before it can show its first screen: the restaurant’s party-size policy, the advance window, the timezone every date and time on this API is expressed in, the currency every amount is denominated in, and the languages the restaurant serves guests in. Requires the reservations:read scope. Read it once at start-up and hold it; it is cheap to revalidate with If-None-Match.

Party size is policy. min_party_size and max_party_size are the range the restaurant accepts online, enforced by POST /v1/reservations and GET /v1/availability as party_size_too_small and party_size_too_large. They do not say a party of that size can be seated: the table inventory decides that, and a size inside the range that no table fits is refused with no_table_available. The sizes that can actually be seated are party_sizes on each day of GET /v1/availability/months; offer those.

The advance window. max_advance_days, last_service_date and current_date let a funnel avoid advance_window_exceeded and date_in_past rather than discover them.

Those policy refusals are defaults, not walls:

  • party_size_too_small, party_size_too_large and advance_window_exceeded are overridable by a key carrying reservations:write:override.
  • date_in_past is not, and neither is no_table_available — no override adds a table.

Per-service facts are on GET /v1/availability. Whether a card guarantee applies, whether a booking is a request, and when online booking closes vary by service, and are disclosed per shift there. card_guarantee_from_party_size and default_cutoff_minutes here are venue-wide summaries, not those answers.

Service-Version
string

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.

Configuration returned

Media typeapplication/json

The restaurant’s booking policy: the limits a request can break, plus the locale and currency every other payload is expressed in. Read it once at start-up and re-read it on a 200; it is cheap to revalidate and it changes whenever a manager changes a setting.

object
object
required

The object type: always configuration.

string
Allowed values: configuration
name
required

The restaurant this API key resolves to. There is no other way to confirm it.

string
public_booking_url
required

The restaurant’s hosted booking page on our side, absolute and per-environment.

Two uses, and the second is the one that matters: it is a booking page for this restaurant you can send a guest straight to, and it is the BASE of the guest self-service page — append /{modification_token} (from POST /v1/reservations?expand=modification_token) and the guest can view, modify or cancel that booking with no credential of yours.

⚠️ Absolute on purpose: a relative path would resolve against whatever origin your funnel is served from and 404. Read it from here rather than hard-coding a host — it differs between environments, and it moves if the restaurant’s slug is changed.

string
country
required

ISO-3166 alpha-2. Phone numbers sent without a country code are normalised against this country.

string
timezone
required

IANA zone. Every service_date and every HH:MM on this API is wall-clock in this zone — never UTC, never the caller’s.

string
currency
required

ISO-4217. The currency every minor-unit amount on this API is denominated in, guarantee quotes included.

string
primary_language
required

The language restaurant-authored text — shift names, guest messages, closure messages — is rendered in when you send no ?locale=. It is also the language a guest created without guest.language is given.

string
Allowed values: fr en de es it nl pt da sv no fi
guest_languages
required

The languages this restaurant maintains guest-facing content in, primary first. This is the exact set ?locale= accepts on GET /v1/availability and GET /v1/availability/months; anything else is a 400 with param: "locale", because a locale the restaurant holds no strings for would silently answer in the primary language instead.

⚠️ It also bounds what a guest can actually be WRITTEN to in: guest.language on a create accepts any language the platform supports and records it on the profile, but the message goes out in the first of that language and primary_language that appears in this list. Sending one outside it is not refused and changes nothing today.

Array<string>
Allowed values: fr en de es it nl pt da sv no fi
min_party_size
required

Smallest party the restaurant accepts online — policy, not a promise of a table (party_sizes on GET /v1/availability/months is what can be seated). A smaller one is refused with party_size_too_small — overridable, so a key carrying reservations:write:override can still place it. Null means the restaurant sets no floor and the rule never fires.

integer
nullable
max_party_size
required

Largest party the restaurant accepts online — policy, not a promise of a table (party_sizes on GET /v1/availability/months is what can be seated). A larger one is refused with party_size_too_large — overridable, so a key carrying reservations:write:override can still place it, which is how a partner books the large party the restaurant agreed to by phone. Null means no ceiling.

integer
nullable
default_party_size
required

The restaurant’s own suggested party size: preselect it. Always between min_party_size and max_party_size.

integer
nullable
current_date
required

Today, in timezone — the date date_in_past is measured against, not the caller’s. An earlier service_date is refused and, unlike the party and window limits, date_in_past can NOT be overridden: a service that has happened cannot be sold. One exception, and it is not an override — a service that started yesterday and is still seating past midnight remains bookable on yesterday’s date.

string format: date
max_advance_days
required

How many days ahead of current_date the restaurant sells. Beyond it, both availability and create answer advance_window_exceeded, which is overridable on the create. Null means the restaurant has no booking rule and the window is not enforced.

integer
nullable
last_service_date
required

current_date + max_advance_days — the last date worth offering, pre-computed so a calendar can be bounded with a string comparison. Null whenever max_advance_days is.

string format: date
nullable
default_cutoff_minutes
required

The house default for how many minutes before a service starts online booking closes; 0 means bookable until the start time, -1 means bookable during the service, and null means the restaurant has no booking rule at all.

⚠️ A DEFAULT, not the enforced value: an individual service, or one date of it, may set its own, and cutoff_passed is decided on that. Read the ENFORCED value from effective_cutoff_minutes on each shift of GET /v1/availability, which resolves the same cascade the create path checks. Use this one only where no shift is in hand — a settings screen, a default in copy.

Availability remains the authoritative answer either way: a slot past its cutoff is simply not listed.

integer
nullable
show_seating_preference
required

Whether the restaurant wants guests asked to choose a seating area. Render the seating step from GET /v1/sections when true; skip it and send no section_id when false.

⚠️ ADVISORY, not a rule: section_id is accepted on availability and on a create either way, and nothing is refused for sending one. It is the restaurant’s preference about its own booking flow, and it is the only place that preference is stated.

boolean
require_guest_email
required

Whether the restaurant asks for a guest e-mail address on its own booking form.

⚠️ ADVISORY, not a rule: this API does NOT enforce it, and a create with no e-mail is accepted whatever it says — see required_guest_fields for what is actually demanded. Use it to mark the same field required in your funnel rather than contradict the restaurant in either direction.

One refusal does involve the address and it is not this flag: a slot carrying a card guarantee always needs one, however this reads, or the create is refused with email_required_for_guarantee — the guest is sent a pay-link by e-mail and cannot complete the booking without it.

boolean
require_guest_phone
required

Whether the restaurant asks for a guest phone number on its own booking form.

⚠️ ADVISORY, not a rule, exactly like require_guest_email: this API does not enforce it.

⚠️ Sending NEITHER an e-mail nor a phone number is accepted and costs the restaurant two things worth knowing: nobody can reach that guest when a service is cancelled, and the booking can never be matched to an existing guest profile, so it creates a new one every time. Send whichever you hold, or identify the guest with guest_id.

boolean
card_guarantee_from_party_size
required

Whether this venue asks guests for a card imprint at all, and from which party size.

null is a promise: no booking made now, on any service or date, is asked for a card — skip the card step entirely for this venue. Either the restaurant uses no card guarantee, or it cannot currently take one.

A number N is only a maybe: some service, on some date, may ask a party of N or more, and no service asks a smaller party. Build the card step, then read guarantee_from_party_size and guarantee on the service in GET /v1/availability for the date the guest picks — that is the exact answer.

It can go from null to a number whenever the restaurant turns guarantees on, with no change on your side: if you keep it for longer than a session, revalidate with the ETag. No amounts or cancel window here; those are per service.

integer
nullable
required_guest_fields
required

Guest fields a create must carry, or it is refused with guest_fields_required. Not required when the create identifies an existing profile by guest_id. This is the ENFORCED list, and it is not the widget’s form policy: require_guest_email / require_guest_phone above are published as advice about the restaurant’s own form and do not bind this API. Only what appears in this array is refused.

Array<string>
Allowed values: first_name last_name
Example
{
"object": "configuration",
"primary_language": "fr",
"guest_languages": [
"fr"
],
"required_guest_fields": [
"first_name",
"last_name"
]
}
Service-Version
string

Dated API version applied to this response

ETag
string

Pass back as If-None-Match to revalidate cheaply

The Service-Version header names a version we do not publish

Media typeapplication/json

The envelope every public-API error answers with, whatever the status.

object
error
required

Every error response carries this one object.

object
type
required

The broad class of the error, from the HTTP status.

  • invalid_request_error: a 400, 403, 404, 409 or 422 — something about the request to change.
  • authentication_error: a 401 — the key is missing, invalid, revoked or expired.
  • rate_limit_error: a 429 — slow down and retry.
  • api_error: any other status, a fault on our side.
string
Allowed values: invalid_request_error authentication_error rate_limit_error api_error
code
required

The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.

string
message
required

A human-readable explanation for the developer. Its wording can change.

string
param

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.

string
doc_url
required

A link to this code in the errors reference. Always present.

string
Example
{
"error": {
"type": "invalid_request_error"
}
}
X-Request-Id
string

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.

Missing or invalid API key

Media typeapplication/json

The envelope every public-API error answers with, whatever the status.

object
error
required

Every error response carries this one object.

object
type
required

The broad class of the error, from the HTTP status.

  • invalid_request_error: a 400, 403, 404, 409 or 422 — something about the request to change.
  • authentication_error: a 401 — the key is missing, invalid, revoked or expired.
  • rate_limit_error: a 429 — slow down and retry.
  • api_error: any other status, a fault on our side.
string
Allowed values: invalid_request_error authentication_error rate_limit_error api_error
code
required

The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.

string
message
required

A human-readable explanation for the developer. Its wording can change.

string
param

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.

string
doc_url
required

A link to this code in the errors reference. Always present.

string
Example
{
"error": {
"type": "invalid_request_error"
}
}

API key lacks the reservations:read scope

Media typeapplication/json

The envelope every public-API error answers with, whatever the status.

object
error
required

Every error response carries this one object.

object
type
required

The broad class of the error, from the HTTP status.

  • invalid_request_error: a 400, 403, 404, 409 or 422 — something about the request to change.
  • authentication_error: a 401 — the key is missing, invalid, revoked or expired.
  • rate_limit_error: a 429 — slow down and retry.
  • api_error: any other status, a fault on our side.
string
Allowed values: invalid_request_error authentication_error rate_limit_error api_error
code
required

The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.

string
message
required

A human-readable explanation for the developer. Its wording can change.

string
param

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.

string
doc_url
required

A link to this code in the errors reference. Always present.

string
Example
{
"error": {
"type": "invalid_request_error"
}
}

Too many requests on the read budget

Media typeapplication/json

The envelope every public-API error answers with, whatever the status.

object
error
required

Every error response carries this one object.

object
type
required

The broad class of the error, from the HTTP status.

  • invalid_request_error: a 400, 403, 404, 409 or 422 — something about the request to change.
  • authentication_error: a 401 — the key is missing, invalid, revoked or expired.
  • rate_limit_error: a 429 — slow down and retry.
  • api_error: any other status, a fault on our side.
string
Allowed values: invalid_request_error authentication_error rate_limit_error api_error
code
required

The specific error, stable and machine-readable, e.g. not_found. Branch on this, not on message.

string
message
required

A human-readable explanation for the developer. Its wording can change.

string
param

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.

string
doc_url
required

A link to this code in the errors reference. Always present.

string
Example
{
"error": {
"type": "invalid_request_error"
}
}
RateLimit-Limit
integer

Requests permitted in the read burst

RateLimit-Remaining
integer

Requests remaining in the read burst

RateLimit-Reset
integer

Seconds until the read bucket refills

RateLimit-Resource
string

Which budget the numbers describe. read here.

Retry-After
integer

Seconds to wait before retrying

X-Request-Id
string

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.