Conventions
These conventions apply to every endpoint in the API reference. Read them once; the resource pages assume them.
Base URL
Section titled “Base URL”All API paths live under /api/* on the production host:
https://thesidedoor.coRequests and responses are JSON. Send Content-Type: application/json on
any request with a body. Authenticated requests send an
Authorization: Bearer <token> header - see Authentication.
Image uploads
Section titled “Image uploads”Multipart uploads are blocked at the edge. Images are uploaded inline as base64 data URLs inside the JSON body - for example a venue logo, a bundle image or an event cover. Pass the data URL in the documented field, e.g.:
{ "logo_url": "data:image/png;base64,iVBORw0KGgoAAAANS..." }Payload size is capped per endpoint, typically between 500 KB and 3 MB.
Oversized images are rejected with a 400.
Errors
Section titled “Errors”Errors return a JSON body with a single error string and an appropriate HTTP
status code:
{ "error": "Party size exceeds the maximum for this rule." }| Status | Meaning |
|---|---|
400 |
Validation error - a field is missing or invalid. |
401 |
Not authenticated, or the session token has expired. |
402 |
Payment required - a card or payment step is needed. |
403 |
Authenticated but not allowed - role or venue-access (ACL) failure. |
404 |
Resource not found. |
409 |
Conflict - the resource is in a state that blocks this action (e.g. a hold already captured). |
429 |
Rate limited - retry after Retry-After. |
500 |
Unexpected server error. |
502 |
Upstream dependency failed. |
503 |
A dependency is unconfigured, or the platform is in maintenance mode. |
Pagination
Section titled “Pagination”List endpoints accept limit (default 50, max 200) and offset query
parameters and return an offset-paged envelope:
{ "data": [ { "id": "bkg_1" }, { "id": "bkg_2" } ], "total": 128, "limit": 50, "offset": 0, "has_more": true}Iterate by incrementing offset by limit while has_more is true.
A few high-volume endpoints support cursor paging instead. Request it with
?paging=cursor and follow the returned cursor value on the next call:
GET /api/.../items?paging=cursor&cursor=eyJpZCI6...ETags and conditional requests
Section titled “ETags and conditional requests”Reference and slowly-changing endpoints (for example the shared reference lists
and your reservations calendar) return an ETag header. Send it back as
If-None-Match and the API replies 304 Not Modified with an empty body when
nothing has changed, saving you the payload:
GET /api/reference/event-types→ 200 OK, ETag: "a1b2c3"
GET /api/reference/event-typesIf-None-Match: "a1b2c3"→ 304 Not ModifiedCaching
Section titled “Caching”- Public endpoints (discovery, widget configs) are edge-cached for roughly 30–120 seconds with stale-while-revalidate. Expect brief propagation delays after a change.
- Authenticated responses are served
private, no-store- never cache a bearer-scoped response in a shared cache. - Static assets are served
public, max-age=31536000, immutable.
Rate limits
Section titled “Rate limits”Sensitive and public endpoints are rate limited per IP (and, for some, per
email). Exceeding a limit returns 429 with a Retry-After header giving the
number of seconds to wait:
HTTP/1.1 429 Too Many RequestsRetry-After: 42
{ "error": "Too many requests. Please try again shortly." }Back off and retry after the indicated delay.
Idempotent finalize endpoints
Section titled “Idempotent finalize endpoints”Payment and hold actions are safe to retry. The .../finalize endpoints
re-read the payment intent and converge on the same outcome, and hold
capture/release are idempotent - repeating a completed action is a no-op, while
an action that contradicts the current state (capturing an already-released
hold, releasing an already-captured one) returns 409. This makes it safe to
retry after a dropped connection without double-charging.
Maintenance mode
Section titled “Maintenance mode”When the platform is put into maintenance mode, /api/* requests return a
branded 503. Treat it as transient and retry later.