Bookings
GET /partner/v1/bookings
Section titled “GET /partner/v1/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 parameter | Required | Meaning |
|---|---|---|
from | no | Overlap filter start: bookings with departure ≥ from |
to | no | Overlap filter end: bookings with arrival ≤ to |
status | no | Exact status (confirmed, option, checked_in, …) |
unit | no | Unit slug |
page | no | 1-based page number, default 1 |
pageSize | no | 1–200, default 100; newest arrival first |
limit | no | Older 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.
GET /partner/v1/bookings/:id
Section titled “GET /partner/v1/bookings/:id”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.
POST /partner/v1/bookings
Section titled “POST /partner/v1/bookings”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.
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" } }'| Field | Required | Notes |
|---|---|---|
unit | yes | Unit slug from GET /units |
arrival / departure | yes | ISO dates, half-open [arrival, departure) |
status | no | confirmed (default), option or draft — the latter two are holds |
adults / children | no | Default 2 / 0 |
extraBed | no | Cot / extra bed; ignored without children |
holdHours | no | Lifetime of a draft/option hold; the agency’s default otherwise |
sourceRef | no | Your own reference, stored alongside the booking |
notes | no | Free text for the agency |
guest | no | firstName, 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.
Refusals
Section titled “Refusals”| HTTP | code | Meaning |
|---|---|---|
| 400 | VALIDATION | Malformed body, or departure not after arrival |
| 404 | NOT_FOUND | Unknown unit slug |
| 422 | MIN_STAY | Below the effective minimum; carries minStay |
| 409 | TURNOVER_BLOCK_CONFLICT | Cleaning block from the previous stay; carries conflict |
| 409 | EXPECTED_EXTENSION_CONFLICT | A current guest is expected to extend into these dates; carries conflicts |
| 409 | BOOKING_CONFLICT | The 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.
POST /partner/v1/bookings/:id/cancel
Section titled “POST /partner/v1/bookings/:id/cancel”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.