Error model
The exact runtime envelope every SeatBuilder error response carries, plus the standard HTTP status codes you should handle.
Error model
Every error response from the SeatBuilder public API follows the same JSON envelope:
{
"statusCode": 400,
"message": "Validation failed",
"errors": { /* see below */ }
}The HTTP status code drives your retry policy; the message is
human-readable; the optional errors map carries field-level
diagnostics for validation failures. The shape is stable: integrations
should match on statusCode first.
Validation errors (400)
Zod validation runs before any controller handler. When a request body violates a schema, the server returns:
{
"statusCode": 400,
"message": "Validation failed",
"errors": {
"name": ["String must contain at least 3 character(s)"],
"draftVersion": ["Expected object, received string"]
}
}The errors map has the following shape:
- Keys are dot-paths into the request body — e.g.,
name,draftVersion,sections.0.rows.2.label. The synthetic key_rootis used for whole-body violations (e.g., the request body itself is the wrong type). - Values are arrays of human-readable Zod messages. A single field can fail multiple constraints (e.g., min length AND format) and each failure is reported as a separate string.
Display these messages directly under the offending form field; the server has already formatted them for UI consumption.
Authentication errors (401)
Returned when the X-Api-Key header is missing, malformed, or hashes
to a key the server doesn't recognise.
{
"statusCode": 401,
"message": "Missing API key"
}The same envelope is returned for the "invalid key" case
("message": "Invalid API key") — the server does not distinguish
unknown keys from forged keys to keep enumeration noisy.
Authorization errors (403)
Returned when the key authenticates but is not allowed to perform the
requested action — wrong workspace, wrong environment, or a key type
that does not have the required scope (e.g., a pk_* publishable key
attempting to create a chart).
{
"statusCode": 403,
"message": "This endpoint does not accept public keys"
}Not found (404)
Returned when the requested chart, event, webhook, or seat does not exist inside the authenticated workspace and environment.
{
"statusCode": 404,
"message": "Chart not found"
}A 404 never leaks data — if a resource exists in a different workspace but matches the requested key, the response is the same 404.
Conflict (409)
Returned when a hold or book request loses a concurrency race. Another caller already holds the seat for this event.
{
"statusCode": 409,
"message": "Seat already held",
"errors": {
"objectLabel": ["Seat A-12 is currently held by another session"]
}
}Retry only after prompting the buyer to choose a different seat — silent retries will not succeed.
Hold expired (410)
Returned when a book request references a hold token whose TTL has elapsed. The hold has already been released back to the inventory.
{
"statusCode": 410,
"message": "Hold has expired"
}Clear the buyer's client-side selection and prompt them to re-pick seats. See Hold seats and confirm at checkout for the full recovery flow.
Server errors (500)
Returned for unhandled exceptions inside the platform. Retry with
exponential backoff; if the error persists, capture the request ID
(X-Request-Id response header) and contact support.
{
"statusCode": 500,
"message": "Internal server error"
}Authentication
How API keys authenticate every SeatBuilder REST call — public vs secret keys, the X-Api-Key header, environments, and workspace scope.
Integration walkthrough
End-to-end integration — create a chart, publish it, run an event, render the SDK, hold a seat, book it, and verify the webhook delivery.