Skip to content

Bookings

Scope read:bookings. Booking rows without guest personal data — dates, status, source, party size and totals only. Guest names and contact details live behind the separate read:guests scope.

Query parameterRequiredMeaning
fromnoOverlap filter start: bookings with departure ≥ from
tonoOverlap filter end: bookings with arrival ≤ to
statusnoExact status (confirmed, option, checked_in, …)
unitnoUnit slug
pageno1-based page number, default 1
pageSizeno1–200, default 100; newest arrival first
limitnoOlder alias for pageSize; still honoured
{
"bookings": [
{
"id": "0191a…",
"unitSlug": "marina-loft-2br",
"unitName": "Marina Loft · 2BR",
"type": "guest",
"status": "confirmed",
"source": "airbnb",
"arrival": "2026-09-10",
"departure": "2026-09-14",
"nights": 4,
"adults": 2,
"children": 1,
"totalAmount": 223650
}
],
"page": 1,
"pageSize": 100,
"totalItems": 428,
"pageCount": 5
}

Filter on type (guest vs owner_stay / maintenance / block) before computing occupancy or revenue — details in the bookings guide.

Scope read:bookings. One booking by its opaque id, same fields as the list. 404 NOT_FOUND if it does not exist or belongs to another agency.

Scope write:bookings. Creates a booking and returns it with 201.

The request runs the same gauntlet as the agency’s own portal: minimum stay, cleaning block after the previous checkout, announced extensions of a current guest, and finally the hard night guard that makes a double booking impossible. None of these can be overridden from here — an agency’s own signal outranks a remote caller’s intent.

Terminal window
curl -X POST https://api.myrentalcalendar.com/partner/v1/bookings \
-H "Authorization: Bearer hr_live_…" \
-H "Content-Type: application/json" \
-d '{
"unit": "marina-loft-2br",
"arrival": "2026-09-10",
"departure": "2026-09-14",
"adults": 2,
"guest": { "firstName": "Nadia", "lastName": "Rahman", "email": "nadia@example.com" }
}'
FieldRequiredNotes
unityesUnit slug from GET /units
arrival / departureyesISO dates, half-open [arrival, departure)
statusnoconfirmed (default), option or draft — the latter two are holds
adults / childrennoDefault 2 / 0
extraBednoCot / extra bed; ignored without children
holdHoursnoLifetime of a draft/option hold; the agency’s default otherwise
sourceRefnoYour own reference, stored alongside the booking
notesnoFree text for the agency
guestnofirstName, lastName, email, phone, nationality. An existing guest with the same e-mail is reused rather than duplicated

There is no price field, by design. The total comes from the same pricing engine as POST /quote — call that first if you need to show a price before booking. An invoice and a landlord statement have to be able to explain every number they carry, and “a partner sent it” is not an explanation. Any price-shaped field in the body is ignored.

Bookings created this way carry source: "partner", so the agency can tell them apart in its own reporting.

HTTPcodeMeaning
400VALIDATIONMalformed body, or departure not after arrival
404NOT_FOUNDUnknown unit slug
422MIN_STAYBelow the effective minimum; carries minStay
409TURNOVER_BLOCK_CONFLICTCleaning block from the previous stay; carries conflict
409EXPECTED_EXTENSION_CONFLICTA current guest is expected to extend into these dates; carries conflicts
409BOOKING_CONFLICTThe nights were taken meanwhile; carries conflict

Treat 409 as “ask again”: re-read availability and offer the guest a different slot. Only BOOKING_CONFLICT means someone else was faster — the other two mean the agency has a reason of its own.

Scope write:bookings. Cancels the booking and releases its nights; the record itself is kept with the reason. Returns the cancelled booking.

{ "reason": "Guest withdrew" }

404 NOT_FOUND for an unknown id. Cancelling something already cancelled is not an error — it answers 200 with the unchanged booking, so a retry after a timeout is safe.

Every write through a key is recorded in the agency’s audit trail with the key as the actor, including the attempts that were refused.