Skip to content

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.

GET /api/v1/public/bookings/

Required scope: bookings:read

Query parameters:

NameTypeDefaultDescription
pageinteger1Page number, 1-indexed
page_sizeinteger50Items per page (max 200)
statusstringExact match on the booking status code (see Booking status values)
check_in_fromdate (YYYY-MM-DD)Returns bookings with check_in_date >= the value
check_in_todate (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):

FieldTypeDescription
idintegerBooking primary key, unique within the tenant
booking_referencestringHuman-readable reference code shown to guests and on invoices
guest_first_namestringGuest first name (may be empty for legacy walk-in bookings)
guest_last_namestringGuest last name (may be empty)
guest_emailstringGuest email (may be empty)
site_idintegerID of the pitch this booking is on
site_numberstringPitch number as displayed on the campsite map (e.g. "A12")
check_in_datedate (YYYY-MM-DD)Arrival date
check_out_datedate (YYYY-MM-DD)Departure date
num_adultsintegerNumber of adult guests
num_youthintegerNumber of youth guests (default 0)
num_childrenintegerNumber of child guests (default 0)
statusstringBooking status code — see Booking status values
total_pricedecimal string (CHF)Server-stored total. For bookings created through this API, this is a placeholder estimate; see Common gotchas
created_atdatetime (ISO 8601, UTC)When the booking record was created

Errors: 401, 403, 429. See Errors and status codes for the response shapes.

Example (curl):

Terminal window
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"])
GET /api/v1/public/bookings/{id}/

Required scope: bookings:read

Path parameters:

NameTypeDescription
idintegerBooking 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):

Terminal window
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()
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:

FieldTypeRequiredDescription
site_idintegeryesID of an existing pitch on the calling tenant
check_in_datedate (YYYY-MM-DD)yesArrival date
check_out_datedate (YYYY-MM-DD)yesDeparture date — must be after check_in_date
num_adultsinteger ≥ 0yesNumber of adult guests
num_youthinteger ≥ 0no (default 0)Number of youth guests
num_childreninteger ≥ 0no (default 0)Number of child guests
guest_first_namestringnoGuest first name
guest_last_namestringnoGuest last name
guest_emailstring (email)noGuest 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:

  • status is "pending".
  • booking_reference is server-generated.
  • total_price is a placeholder — see Common gotchas.

Errors:

StatusBodyWhen
400{"detail": "site_not_found"}site_id is missing, malformed, or does not match a pitch on the calling tenant
400Field-keyed validation errorsBody is missing required fields or fails type/range validation — see Errors and status codes
401, 403, 429Standard auth/throttle errors

Example (curl):

Terminal window
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"])

The status field uses one of these stable codes:

CodeMeaning
pendingAwaiting operator confirmation. The default for bookings created through this API.
confirmedOperator has accepted the booking.
cancelledBooking was cancelled before the stay.
completedStay has finished and was checked out.
no_showGuest 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.

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.