There is no built-in API sandbox. Use a dedicated test business locally. Reservation creation can send notifications or create a deposit checkout; configure test mail and payment credentials before experimenting.
Authentication & access
Every operation requires Authorization: Bearer <your-token>. The token selects the business; you do not pass a business ID. The business must be active and its Developer API add-on enabled.
Scope
Permits
Additional add-on
catalog:read
Read the default menu
None
orders:read
List and read orders
Online Ordering
reservations:read
List and read reservations
Reservations
reservations:create
Read bookable services, check slots and create reservations
Reservations
Use the smallest set of scopes needed. Tokens can have an expiry date and can be revoked by deleting them in the admin. Legacy tokens with no stored scopes retain read permissions only.
Rate limit: 60 requests per minute. On a 429 response, wait for the Retry-After interval before retrying.
Use service IDs and option IDs returned by the catalogue. Check a date in the business's local timezone, then confirm the service, time and customer details with the customer before submitting.
Served HQ calculates prices and duration and checks availability again when you submit. A slot response is not a reservation or a guaranteed hold.
Groups: pass party_size when checking slots. Some businesses can see only a set number of people per time slot; a larger group then needs back-to-back slots, and only start times where the whole run is free are returned. Service prices are per person: each created line reports quantity and unit_price_pence, with price_pence as the line total. Restaurant table bookings are not priced per person.
Read the outcome before responding to the customer
201 means a reservation was created in pending state, awaiting review. 202 with payment_required returns a checkout_url for a deposit; the reservation has not yet been created. Neither result means a confirmed appointment.
Some services are enquiry-only and have no booked date. Home visits may require a service address, and businesses may require custom fields. Respect service-specific rules and validation errors.
Use a unique Idempotency-Key for each booking attempt. Reuse it with the same body for network retries. Reusing the key with a changed body returns a conflict.
03 / REFERENCE
Available endpoints
All paths below are relative to this application's host. Monetary fields ending in _pence are integer minor-unit amounts; interpret them using your business currency.
8 endpoints
GET/api/v1/menu
Get the business menu
Returns the authenticated business's default menu grouped by category.
An empty `data` array is returned when no default menu exists.
Only available fields are returned; this is not a complete catalogue
or public discovery contract.
Scope: catalog:readAdd-on: Developer API only
Request example
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
Returns orders belonging to the authenticated business. Results are
ordered newest first and paginated. `since` accepts a date or timestamp
understood by the application.
Scope: orders:readAdd-on: Online ordering
Parameters
Name
Location
Details
per_page
query
Number of records per page. integer. Min: 1. Max: 100. Default: 25.
Return orders created at or after this date or timestamp. string (date-time).
Request example
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
Returns one order belonging to the authenticated business.
Scope: orders:readAdd-on: Online ordering
Parameters
Name
Location
Details
orderrequired
path
Numeric order identifier. integer (int64). Min: 1.
Request example
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
Returns the public, available services and their option groups for booking.
Scope: reservations:createAdd-on: Reservations
Request example
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
Returns slots calculated for the selected services on a business-local date.
When the business sets a number of people per time slot, a group larger
than that capacity needs one run of the services per wave of people,
back to back within one shift (for example 3 people at 2 per slot need
two consecutive runs). Only start times where every run fits are returned.
Omitting party_size checks availability for one person, which matches the
behaviour before contract 1.1.0.
Scope: reservations:createAdd-on: Reservations
Parameters
Name
Location
Details
daterequired
query
string (date).
menu_item_ids
query
Menu item IDs whose combined duration should be checked. array. Max items: 20.
party_size
query
Number of people to fit (added in 1.1.0). Defaults to 1. integer. Min: 1. Max: 50. Default: 1.
Encode service arrays as menu_item_ids[]=42&menu_item_ids[]=43. Date and time values are business-local; select a date within that business's booking window.
Request example
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
Returns reservations belonging to the authenticated business. Results
are ordered by reserved date and time. Enquiry-only records may have a
null reserved date and are identified by `is_enquiry_only`.
Scope: reservations:readAdd-on: Reservations
Parameters
Name
Location
Details
per_page
query
Number of records per page. integer. Min: 1. Max: 100. Default: 25.
Filter by reservation status. string. Max length: 40.
from
query
Return reservations on or after this business date. string (date).
Request example
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
Creates a pending reservation after validating the selected public
services, option selections, booking window, business ownership of a
staff member, and slot availability. The client must send a unique
Idempotency-Key. Repeating the same request with the same key replays
the original response; reusing a key with a different body is a 409.
Prices and duration supplied by a client are ignored.
From contract 1.1.0, services are priced per person: each item's
price_pence is the unit price (service plus selected options) times
party_size, reported as quantity and unit_price_pence. Restaurant
table bookings are not priced per person. When the business sets a
number of people per time slot, total_duration_minutes covers every
back-to-back run the group needs and the whole run must be free;
otherwise the request fails with slot_unavailable. Deposits that a
business sets per service are taken per person.
Scope: reservations:createAdd-on: Reservations
Parameters
Name
Location
Details
Idempotency-Keyrequired
header
A client-generated key reused for safe retries of the same request. string. Max length: 255.
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
Returns one reservation belonging to the authenticated business.
Scope: reservations:readAdd-on: Reservations
Parameters
Name
Location
Details
reservationrequired
path
integer (int64). Min: 1.
Request example
Illustrative IDs and customer details. Replace them with your test business's data. Shell syntax shown for Bash / Git Bash; on Windows use curl.exe and adapt line continuations for your shell.
No endpoints match. Try “menu”, “availability” or “reservations”.
04 / EVENT DELIVERY
Webhooks: react to business changes
Served HQ sends an HTTP POST to your receiver when a subscribed event happens. Use it to notify an agent, update a connected dashboard or trigger your automation without polling.
Set up a subscription
Enable the business's Developer API add-on and open Webhooks in the business admin.
Add your public HTTPS receiver URL and select the events to receive.
Copy the subscription's signing secret from the admin and store it on your receiver's server. This is separate from your API bearer token.
Run the Served HQ queue worker and trigger a change using a test business. Check the subscription's last delivery status in the admin.
Destinations must use a public HTTPS hostname on port 443 that resolves to public IPv4 addresses. Localhost, private IPs, IPv6-only destinations and redirects are not supported. For local receiving experiments, use a public HTTPS tunnel to your test receiver; never disable destination validation.
What arrives at your endpoint
Header
Meaning
Content-Type
application/json
X-ServedHQ-Event
The event name, also present in the signed body.
X-ServedHQ-Timestamp
Unix timestamp in seconds for this delivery attempt.
X-ServedHQ-Signature-V2
Lowercase hex HMAC-SHA256 of timestamp + "." + raw body, using the subscription secret. Recommended.
X-ServedHQ-Signature
Legacy lowercase hex HMAC-SHA256 of the raw body only. It does not bind the delivery timestamp.
The JSON envelope contains event, id (UUID), timestamp (ISO 8601 event time) and data. The body and event ID stay the same across retries; the delivery timestamp header and V2 signature are regenerated. Validate freshness against the header timestamp, not the event timestamp in the body.
Events & payload examples
These are illustrative payloads, not a live delivery log. Events contain a subset of record fields. Use the matching GET order or reservation endpoint with its read scope and add-on to retrieve more details.
order.created — Order created
A new order was created. status is the creation status; this event does not assert that the order is paid.
An order's fulfilment status changed. Values include pending, confirmed, preparing, ready, completed and cancelled. This event does not report payment changes.
A reservation record was created. This is not a confirmation event. Enquiry-only records may have a null date and time. service_items may be empty; item IDs and durations may be null for some records.
No dedicated stock-change, payment-settled, refund or reservation-rescheduled event is currently offered. Subscription creation, pausing and deletion happen in the admin; they are not API operations.
Verify the signature
Read the raw HTTP body before decoding JSON. Check the timestamp is within five minutes of your server's clock, calculate the V2 HMAC and compare in constant time. Changing whitespace or re-encoding the JSON before verification will invalidate the signature.
PHP example: pass $request->getContent(), the timestamp and V2 headers, and your stored secret to this function. Reject invalid requests before applying any business changes. Use the event name in the signed body for routing.
<?php
// Signature verification only; call this with the exact, unmodified HTTP body.
// Load the subscription's secret from secure server-side configuration.
function verifyServedHqWebhook(
string $rawBody,
string $timestamp,
string $signatureV2,
string $secret,
?int $now = null,
): array {
if ($secret === '' || ! ctype_digit($timestamp)
|| abs(($now ?? time()) - (int) $timestamp) > 300
|| ! preg_match('/\A[a-f0-9]{64}\z/', $signatureV2)) {
throw new RuntimeException('Invalid webhook authentication.');
}
$expected = hash_hmac('sha256', $timestamp.'.'.$rawBody, $secret);
if (! hash_equals($expected, $signatureV2)) {
throw new RuntimeException('Invalid webhook signature.');
}
$event = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
if (! is_array($event) || ! is_string($event['id'] ?? null)
|| ! is_string($event['event'] ?? null) || ! is_array($event['data'] ?? null)) {
throw new RuntimeException('Invalid webhook envelope.');
}
// Receiver must now persist using a unique (subscription, event ID) key.
// A valid signature alone does not prevent duplicate processing.
return $event;
}
Acknowledge, deduplicate & retry
Verify the request, then durably store it using a unique key combining the subscription identity and event id.
Return a 2xx response promptly after storing it, including for an already stored duplicate. Process the stored event asynchronously.
Do not rely on delivery order. Reconcile the current record through the read API where needed.
Delivery has a 5-second connection timeout and a 10-second request timeout. The job permits up to three attempts total; normal queued retry delays are 10 seconds and then 60 seconds. Worker configuration can affect retry timing or reduce attempts. Non-2xx responses and network failures cause retries; redirects are rejected.
After retries are exhausted, delivery can be lost. Monitor the last delivery status and reconcile records through the read API; there is no public webhook delivery-history or replay endpoint. Disabled/deleted subscriptions, inactive businesses and disabled or expired Developer API access stop delivery.
Errors & retries
Errors can contain error and a machine-readable code. Validation errors use message and field-level errors.
Status
What to do
400
Supply a valid Idempotency-Key for booking creation.
401
Check the bearer token and its expiry/revocation.
403
Check business access, required add-ons and token scopes.
404
Check the numeric record ID belongs to the authenticated business.
409
Recheck booking availability or resolve the idempotency conflict. Do not blindly retry a changed basket under the same key.
422
Correct the fields identified in the validation response.
429
Wait for Retry-After; back off repeated requests.
Lists return data and pagination meta: current page, last page and total. Use page and per_page (default 25, maximum 100).
Response & request schemas
Expand a schema to inspect its fields. Follow linked types for nested records.
Connect a booking agent to services and availability, submit reservation requests, or build a dashboard/export that reads your menu, orders and reservations.
Current API boundaries
Order creation, menu or stock updates, cancellation/rescheduling, customer mutations and refunds are not exposed as API operations. The menu endpoint reports the stored availability flag, not full stock levels or effective daily-limit availability.
Outbound webhooks can be configured in the business admin. Webhook management is not an API operation in this version.