Skip to content

Errors and status codes

The CampOne API uses standard HTTP status codes and two predictable JSON error shapes. Read this page once and you will be able to handle errors uniformly across every endpoint.

The API returns one of two JSON shapes when something goes wrong.

Used for authentication, authorization, not-found, throttling, server errors, and most domain-level errors:

{ "detail": "invalid_key" }

The value is either a short machine code (e.g. invalid_key, site_not_found) or a human-readable sentence — see the documented error codes below.

POST endpoints validate the request body before processing. If validation fails, the API returns 400 Bad Request with one entry per offending field:

{
"check_in_date": ["This field is required."],
"num_adults": ["Ensure this value is greater than or equal to 0."]
}

Each value is an array of one or more error messages for that field. Top-level non_field_errors may also appear if the validation rule isn’t tied to a single field.

CodeWhen
200 OKSuccessful GET
201 CreatedSuccessful POST that created a resource
400 Bad RequestValidation error on the body, or a documented domain error such as site_not_found
401 UnauthorizedMissing, malformed, expired, or revoked API key
403 ForbiddenValid key but missing the required scope
404 Not FoundThe resource does not exist, or it exists but belongs to a different tenant
429 Too Many RequestsPer-key rate limit exceeded — see Rate limits
500 Internal Server ErrorServer-side fault — retry with exponential backoff and report to support if it persists

The codes below are stable strings — your code can match on them without parsing prose. Anything else that lands in detail should be treated as a generic message, not a contract.

CodeStatusWhere
invalid_key401Any endpoint, when the bearer token is missing, malformed, or doesn’t match a key on file
key_inactive401Any endpoint, when the key has been revoked or has passed its expiry
site_not_found400POST /api/v1/public/bookings/, when site_id does not match a site on the calling tenant
not_found404Detail endpoints (e.g. GET /api/v1/public/bookings/{id}/), when the resource doesn’t exist or belongs to another tenant

Every API key is bound to exactly one tenant. The API filters all queries by that tenant before they reach the database, so:

  • A GET for a resource that exists but belongs to a different tenant returns 404, not 403. The API deliberately does not distinguish “not yours” from “doesn’t exist” — that would leak the existence of resources across tenants.
  • Resource IDs are not globally unique across tenants. Booking ID 42 for tenant A and booking ID 42 for tenant B are different bookings. Never assume an ID you obtained from one key is meaningful with another.
  • A POST body that references an ID belonging to a different tenant (e.g. site_id on a booking creation) is rejected as if the ID didn’t exist (400 site_not_found).

The current API version (v1) does not support idempotency keys. In particular:

  • POST /api/v1/public/bookings/ is not safe to retry blindly — a network timeout that obscures a successful creation will leave you with a duplicate booking on retry.
  • If a POST times out, query the list endpoint with appropriate filters before retrying, to confirm whether the resource was actually created.

A proper idempotency-key header is on the roadmap. Until it ships, treat creation calls as side-effecting and design your retry logic accordingly.