Bookings
A booking is a guest stay on a single pitch (site) for a date range. The bookings endpoints let an integration enumerate existing bookings, look up a specific one, and submit new pending reservations that an operator will confirm in the admin console.
The public booking object is a deliberately small projection of the internal booking record — the fields below are the contract, and they will not be renamed, removed, or retyped within v1.
List bookings
Section titled “List bookings”GET /api/v1/public/bookings/Required scope: bookings:read
Query parameters:
| Name | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number, 1-indexed |
page_size | integer | 50 | Items per page (max 200) |
status | string | — | Exact match on the booking status code (see Booking status values) |
check_in_from | date (YYYY-MM-DD) | — | Returns bookings with check_in_date >= the value |
check_in_to | date (YYYY-MM-DD) | — | Returns bookings with check_in_date <= the value |
Default order: created_at descending — newest bookings first. See Pagination and filtering for the full pagination contract.
Response 200:
{ "count": 137, "next": "https://api.campone.ch/api/v1/public/bookings/?page=2", "previous": null, "results": [ { "id": 4821, "booking_reference": "B-7K2QXA", "guest_first_name": "Anna", "guest_last_name": "Müller", "guest_email": "anna.mueller@example.ch", "site_id": 312, "site_number": "A12", "check_in_date": "2026-07-14", "check_out_date": "2026-07-21", "num_adults": 2, "num_youth": 0, "num_children": 1, "status": "confirmed", "total_price": "385.00", "created_at": "2026-04-26T09:14:22.481Z" } ]}Response fields (per result):
| Field | Type | Description |
|---|---|---|
id | integer | Booking primary key, unique within the tenant |
booking_reference | string | Human-readable reference code shown to guests and on invoices |
guest_first_name | string | Guest first name (may be empty for legacy walk-in bookings) |
guest_last_name | string | Guest last name (may be empty) |
guest_email | string | Guest email (may be empty) |
site_id | integer | ID of the pitch this booking is on |
site_number | string | Pitch number as displayed on the campsite map (e.g. "A12") |
check_in_date | date (YYYY-MM-DD) | Arrival date |
check_out_date | date (YYYY-MM-DD) | Departure date |
num_adults | integer | Number of adult guests |
num_youth | integer | Number of youth guests (default 0) |
num_children | integer | Number of child guests (default 0) |
status | string | Booking status code — see Booking status values |
total_price | decimal string (CHF) | Server-stored total. For bookings created through this API, this is a placeholder estimate; see Common gotchas |
created_at | datetime (ISO 8601, UTC) | When the booking record was created |
Errors: 401, 403, 429. See Errors and status codes for the response shapes.
Example (curl):
curl -H "Authorization: Bearer ck_a1b2c3d4XXXXXXXXXXXXXXXXXXXXXXXX" \ "https://api.campone.ch/api/v1/public/bookings/?check_in_from=2026-07-01&check_in_to=2026-07-31"Example (Python):
import requests
r = requests.get( "https://api.campone.ch/api/v1/public/bookings/", headers={"Authorization": "Bearer ck_a1b2c3d4XXXXXXXXXXXXXXXXXXXXXXXX"}, params={"check_in_from": "2026-07-01", "check_in_to": "2026-07-31"},)r.raise_for_status()data = r.json()for booking in data["results"]: print(booking["booking_reference"], booking["site_number"], booking["status"])Retrieve a booking
Section titled “Retrieve a booking”GET /api/v1/public/bookings/{id}/Required scope: bookings:read
Path parameters:
| Name | Type | Description |
|---|---|---|
id | integer | Booking ID, as returned in the list endpoint |
Response 200: A single booking object, with the same fields as a results[] entry from the list endpoint.
Errors: 401, 403, 404 ({"detail": "not_found"} when the booking does not exist or belongs to another tenant), 429.
Example (curl):
curl -H "Authorization: Bearer ck_a1b2c3d4XXXXXXXXXXXXXXXXXXXXXXXX" \ "https://api.campone.ch/api/v1/public/bookings/4821/"Example (Python):
import requests
r = requests.get( "https://api.campone.ch/api/v1/public/bookings/4821/", headers={"Authorization": "Bearer ck_a1b2c3d4XXXXXXXXXXXXXXXXXXXXXXXX"},)r.raise_for_status()booking = r.json()Create a booking
Section titled “Create a booking”POST /api/v1/public/bookings/Required scope: bookings:write
Creates a booking in pending status with source = "online". An operator confirms it in the admin console; that confirmation step also recalculates the price using the platform’s pricing engine.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
site_id | integer | yes | ID of an existing pitch on the calling tenant |
check_in_date | date (YYYY-MM-DD) | yes | Arrival date |
check_out_date | date (YYYY-MM-DD) | yes | Departure date — must be after check_in_date |
num_adults | integer ≥ 0 | yes | Number of adult guests |
num_youth | integer ≥ 0 | no (default 0) | Number of youth guests |
num_children | integer ≥ 0 | no (default 0) | Number of child guests |
guest_first_name | string | no | Guest first name |
guest_last_name | string | no | Guest last name |
guest_email | string (email) | no | Guest email |
Fields not listed (status, total_price, booking_reference, created_at) are server-assigned and ignored if sent.
Example request body:
{ "site_id": 312, "check_in_date": "2026-07-14", "check_out_date": "2026-07-21", "num_adults": 2, "num_children": 1, "guest_first_name": "Anna", "guest_last_name": "Müller", "guest_email": "anna.mueller@example.ch"}Response 201: The newly created booking, in the same shape as a list result. Notable defaults on the returned object:
statusis"pending".booking_referenceis server-generated.total_priceis a placeholder — see Common gotchas.
Errors:
| Status | Body | When |
|---|---|---|
400 | {"detail": "site_not_found"} | site_id is missing, malformed, or does not match a pitch on the calling tenant |
400 | Field-keyed validation errors | Body is missing required fields or fails type/range validation — see Errors and status codes |
401, 403, 429 | — | Standard auth/throttle errors |
Example (curl):
curl -X POST https://api.campone.ch/api/v1/public/bookings/ \ -H "Authorization: Bearer ck_a1b2c3d4XXXXXXXXXXXXXXXXXXXXXXXX" \ -H "Content-Type: application/json" \ -d '{ "site_id": 312, "check_in_date": "2026-07-14", "check_out_date": "2026-07-21", "num_adults": 2, "num_children": 1, "guest_first_name": "Anna", "guest_last_name": "Müller", "guest_email": "anna.mueller@example.ch" }'Example (Python):
import requests
r = requests.post( "https://api.campone.ch/api/v1/public/bookings/", headers={"Authorization": "Bearer ck_a1b2c3d4XXXXXXXXXXXXXXXXXXXXXXXX"}, json={ "site_id": 312, "check_in_date": "2026-07-14", "check_out_date": "2026-07-21", "num_adults": 2, "num_children": 1, "guest_first_name": "Anna", "guest_last_name": "Müller", "guest_email": "anna.mueller@example.ch", },)r.raise_for_status()booking = r.json()print(booking["booking_reference"], booking["status"])Booking status values
Section titled “Booking status values”The status field uses one of these stable codes:
| Code | Meaning |
|---|---|
pending | Awaiting operator confirmation. The default for bookings created through this API. |
confirmed | Operator has accepted the booking. |
cancelled | Booking was cancelled before the stay. |
completed | Stay has finished and was checked out. |
no_show | Guest never arrived. |
Treat any value outside this list as unknown and do not branch on it — additional codes may be added in a future minor version.
Common gotchas
Section titled “Common gotchas”total_price from POST is a placeholder. When a booking is created through the public API, total_price is calculated as base_price_per_night × nights from the pitch and stored on the record. It does not account for seasonal pricing, occupancy modifiers, tourist tax, add-ons, or any of the rules the admin pricing engine applies on confirmation. If your integration needs the final figure, read the booking again after the operator has confirmed it (the status will have moved off pending), or pull the matching invoice from GET /api/v1/public/invoices/.
Tenant isolation on site_id. A site_id from one tenant is meaningless for another tenant’s key — pitch IDs are scoped per tenant, and a foreign ID returns 400 site_not_found, not a useful cross-tenant error. See Errors and status codes for details.
No idempotency keys in v1. Retrying a POST after a network timeout can create duplicate bookings. If a create call fails to return cleanly, query the list endpoint (filtering by check_in_from / check_in_to and matching guest details) before resubmitting.