Retrieve a guest
const url = 'https://api.useservice.app/v1/guests/example';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://api.useservice.app/v1/guests/example \ --header 'Authorization: Bearer <token>'Returns one guest profile from the restaurant’s guest book: names, contact details, the
restaurant’s own flags (vip, blacklisted, allergies, dietary preferences, staff notes)
and the counted visit history. The same object ?expand=guest embeds on a reservation.
Requires the guests:read scope; a key without it is refused 403 insufficient_scope,
whatever else it carries.
Merged profiles resolve here. When two profiles are merged, the absorbed one’s
gst_… keeps working and returns the SURVIVING profile — under the survivor’s own id,
not the one you asked for. So an id you stored never breaks, and the way to notice a
merge is that the id you get back differs from the one you sent. A guest.merged
webhook announces it as it happens.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The guest’s public id, gst_…. The public id of a profile that has since been merged away also resolves, to the surviving profile.
Header Parameters
Section titled “Header Parameters”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.
Responses
Section titled “Responses”Guest found
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.
Example
{ "object": "guest", "language": "fr", "source": "manual"}Headers
Section titled “Headers”Dated API version applied to this response
The Service-Version header names a version we do not publish
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 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.
API key lacks the guests:read 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" }}No such guest
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 read 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 read burst
Requests remaining in the read burst
Seconds until the read bucket refills
Which budget the numbers describe. read 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.