Bookings
A booking represents a guest or resident’s stay in one of your units, from the moment it is requested through to checkout, cancelation, or termination. A booking carries the contractual stay window, the people on it, its commercial terms (rate, discounts, optional services), its payment and vetting state, and a record of what actually happened physically (when the resident arrived and departed).
Bookings are the anchor point for most operational activity in the Lavanda platform. A unit’s availability, a guest’s messages, an invoice’s line items, and a checklist’s tasks are all reached through, or scoped to, a booking.
Key Concepts
Section titled “Key Concepts”Booking status
Section titled “Booking status”A booking moves through a status lifecycle as it is requested, confirmed, occupied, and closed out:
INQUIRY, REQUESTED, RESERVED, TENTATIVE, TENTATIVE_EXPIRED, AWAITING_PAYMENT, CONFIRMED, CHECKED_IN,
CHECKED_OUT, DECLINED, EXPIRED, CANCELED, TERMINATED, CLOSED.
Warning:
CHECKED_INandCHECKED_OUTare deprecated. They are not stored lifecycle statuses: a confirmed booking reportsCHECKED_INonce an arrival is recorded or its check-in date has passed, andCHECKED_OUTonce a departure is recorded or its check-out date has passed. That means a resident who never arrived can still reportCHECKED_IN, and one who has not left can reportCHECKED_OUT. ReadoccupancyStatusto find out whether the resident is actually in residence. Once these two values are removed, those bookings will reportCONFIRMED. We will announce the removal date before it happens.
A tentative booking is a soft hold with a time-to-live (its bookingTtl); it must be confirmed before that TTL
expires or it is automatically expired. See Tentative bookings below.
Three layers of dates: contract, scheduled, and actual
Section titled “Three layers of dates: contract, scheduled, and actual”A booking tracks three distinct kinds of dates, and the API keeps them intentionally separate:
| Layer | Fields | What it means |
|---|---|---|
| Contract | checkIn, checkOut (aliased as contractStartDate, contractEndDate) |
The legal tenancy window agreed with the guest. This is the booking’s binding stay window. |
| Scheduled | scheduledMoveInAt, scheduledMoveOutAt |
The planned physical move date and time. Defaults to the contract window (at the property’s check-in/check-out time) but can be overridden, for example when a guest asks to move in a few hours later than their contract start. |
| Actual | arrivedAt, departedAt |
When the resident actually, physically arrived and departed, recorded by markArrived and markDeparted. Null until recorded. |
Keeping these separate means a late arrival, an early departure, or a rescheduled move-in never overwrites the contract dates you agreed with the guest.
Occupancy status
Section titled “Occupancy status”occupancyStatus is the recorded physical-presence state of the booking: whether the resident is currently checked
in, checked out, marked as a no-show, or temporarily away.
Note:
occupancyStatusis only ever set by an explicit action (marking arrived, marking departed, or flagging a no-show). It is never inferred from the contract or scheduled dates. A booking whose check-in date has passed but whose resident was never marked as arrived still reportsoccupancyStatus: null.
| Value | Description |
|---|---|
CHECKED_IN |
The resident has physically arrived and not yet departed |
CHECKED_OUT |
The resident has physically departed |
NO_SHOW |
The resident did not arrive within the expected check-in window |
AWAY |
The resident is temporarily away from the unit |
OVERSTAY |
The resident did not depart within the expected check-out window |
checkedInStatus is a related, coarser field covering the same ground (NOT_CHECKED_IN, CHECKED_IN,
CHECKED_OUT, NO_SHOW, ABSCONDED). Prefer occupancyStatus for new integrations; checkedInStatus is kept for
backward compatibility.
canCheckIn and canCheckOut tell you, for a given booking, whether it is currently appropriate to mark it arrived
or departed (confirmed, not yet arrived or departed, and the property-local date is due), which is useful for
deciding whether to show a check-in or check-out action in your own UI. Gate check-in on canCheckIn, not on
scheduledMoveInAt: the scheduled move-in can be set earlier than the contract check-in date. The markArrived /
markDeparted mutations do not enforce these conditions, except that markArrived refuses an arrival before the
contract check-in date; see Recording arrival and departure below.
Tentative bookings
Section titled “Tentative bookings”A newly created booking can be tentative: a soft hold on a unit that must be confirmed before its time-to-live
(bookingTtl) expires. Use confirmTentativeBooking to turn it into a CONFIRMED booking, or
expireTentativeBooking to release the hold early. If neither happens before the TTL elapses, the booking is
automatically transitioned to TENTATIVE_EXPIRED.
Relocation, moving, and splitting
Section titled “Relocation, moving, and splitting”relocationPolicy is the operator’s stated intent for whether a booking may be moved off its current unit
(UNRESTRICTED by default, or LOCKED to pin it in place, for example after a guest was relocated for accessibility
reasons). relocatable reflects whether the booking can currently be moved, combining that policy with structural
eligibility checks.
moveBookingrelocates all or part of a booking’s stay from one unit to another.splitBookingdivides a booking’s stay into multiple segments, each pinned to its own unit and date range, for example when a guest needs to change rooms partway through their stay.
Both operations run asynchronously; see Moving and splitting a booking.
Canceling and terminating a booking
Section titled “Canceling and terminating a booking”There are two ways a confirmed booking stops early:
- Direct cancellation (
cancelBooking) cancels a booking immediately. It is scoped to direct bookings and is not a reviewable, multi-party workflow. - Cancelation and termination requests are an explicit, reviewable alternative: one caller opens a request, and another (or the same caller, if permitted) approves, declines, or withdraws it. A cancelation request applies to a booking whose stay has not started; a termination request ends a booking whose stay has already started. Both are per-workspace opt-in features with their own eligibility rules, permissions, and webhook events. See Cancelation Requests for the pre-stay workflow and Termination Requests for the in-stay workflow.
Group bookings
Section titled “Group bookings”Related bookings, for example multiple rooms booked together for the same stay, can be grouped under a shared
context reachable via Booking.context. updateGroupBookingName renames the group.
Contacts and roles
Section titled “Contacts and roles”A booking’s contacts connection lists every guest, guarantor, and booking agent attached to it, each with a role
(for example lead guest, guest, guarantor, or booking agent) and the underlying CRM contact. addContactsToBooking
and removeContactFromBooking manage this list; changeBookingLeadGuest reassigns which contact is the lead guest.
See Contacts for the CRM contact model itself.
Discounts and optional services
Section titled “Discounts and optional services”A booking can carry coupon-backed discounts (discounts, applied and removed via applyDiscount, removeDiscount,
and redeemCoupon) and optional services (services, managed via addOptionalServices, updateOptionalServices,
and removeOptionalServices), both of which feed into the booking’s commercial value alongside its accommodation
charge.
Checklists
Section titled “Checklists”Every booking can carry a checklist of operational tasks (for example vetting or key handover steps), reachable via
Booking.checklist. See Checklists below.
GraphQL API
Section titled “GraphQL API”The Booking type
Section titled “The Booking type”The fields below are grouped by theme. Every field is nullable unless marked !.
Identity and status
Section titled “Identity and status”| Field | Type | Description |
|---|---|---|
id |
String! |
The booking’s unique identifier. Kept as String rather than ID for backward compatibility with existing clients. |
status |
BookingStatusType |
The booking’s status (see Booking status). The CHECKED_IN and CHECKED_OUT values are deprecated; use occupancyStatus instead. |
confirmationCode |
String |
The confirmation code of the booking |
externalBookingId |
String |
The booking’s ID from an external source, when the booking originated on another platform |
platform |
String |
The platform the booking originated on |
createdAt |
ISO8601DateTime! |
When the booking was created |
updatedAt |
ISO8601DateTime! |
When the booking was last updated |
editable |
Boolean |
Whether the booking is currently editable |
cancelable |
Boolean |
Whether the booking is cancelable via direct cancellation |
approvable |
Boolean |
Whether the booking can be approved by the host, for enquiry-based bookings awaiting host acceptance |
Dates and occupancy
Section titled “Dates and occupancy”| Field | Type | Description |
|---|---|---|
checkIn / checkOut |
ISO8601Date |
The contractual check-in and check-out dates |
contractStartDate / contractEndDate |
ISO8601Date |
Aliases of checkIn / checkOut |
scheduledMoveInAt / scheduledMoveOutAt |
ISO8601DateTime |
The planned physical move date and time |
arrivedAt / departedAt |
ISO8601DateTime |
When the resident actually arrived and departed |
occupancyStatus |
OccupancyStatusType |
The recorded physical-presence state (see Occupancy status) |
checkedInStatus |
CheckedInStatusType |
A coarser, legacy presence state |
canCheckIn / canCheckOut |
Boolean! |
Whether the booking is eligible to be marked arrived / departed today |
plannedArrival / plannedDeparture |
String |
The guest’s stated planned arrival and departure time |
nightsCount |
Int |
The number of nights of the booking |
Guests and contacts
Section titled “Guests and contacts”| Field | Type | Description |
|---|---|---|
guestsCount |
Int |
The number of guests on the booking |
contacts |
BookingContact connection |
The guest, guarantor, and booking-agent contacts on the booking |
bookingAgent |
CrmContact |
The booking agent associated with the booking, if any |
guarantorInformations |
[BookingGuarantorInformation!]! |
Typed booking-to-guarantor relationships |
leadGuestChangeAbility |
LeadGuestChangeAbility! |
Whether the current caller can change the lead guest, and why not if disabled |
Contract, relocation, and structure
Section titled “Contract, relocation, and structure”| Field | Type | Description |
|---|---|---|
contractType |
ContractTypeEnum |
The type of contract (short-term licence, AST, or other) |
stayPurpose |
StayPurposeEnum |
The purpose of the stay (holiday, student, or residential) |
relocationPolicy |
BookingRelocationPolicy! |
Operator intent on whether the booking may be relocated |
relocatable |
Boolean |
Whether the booking can currently be relocated |
accommodations |
[Accommodation!] |
The unit allocation history behind the booking, including the current one |
product |
Product |
The product the booking was made against |
context |
BookingContext |
The group of related bookings this booking belongs to, if any |
contracts |
[Contract!] |
The booking’s e-signed contracts, with their envelope and e-signing account details |
Commercial and payment
Section titled “Commercial and payment”| Field | Type | Description |
|---|---|---|
currentContractValue |
ContractValue |
The booking’s current commercial value |
customBillingCycle |
Boolean! |
Whether the booking uses a custom billing cycle (instalment plan) |
instalmentDriven |
Boolean! |
Whether the billing cycle carries authoritative per-instalment amounts |
billingPeriods |
BillingPeriod connection |
The booking’s billing periods |
discounts |
BookingDiscount connection |
The coupon-backed discounts applied to the booking |
services |
BookingOptionalService connection |
The optional services applied to the booking |
paymentStatus |
PaymentStatusType |
The booking’s payment status |
downPaymentStatus |
DownPaymentStatusType |
The booking’s down payment status |
sepaStatus |
SepaStatusType |
The booking’s SEPA mandate status |
vetting |
Vetting |
The booking’s vetting state |
Cancelation and termination
Section titled “Cancelation and termination”| Field | Type | Description |
|---|---|---|
cancellationReason |
String |
The reason recorded if the booking was canceled |
cancelationReasons |
[BookingCancelationReasonEnum!] |
Cancelation reasons applicable given the booking’s current timing |
cancelationPolicy |
BookingCancellationPolicy |
The cancelation policy that applies to the booking |
cancelationRequests |
connection | All cancelation requests opened against the booking. See Cancelation Requests. |
terminationRequests |
connection | All termination requests opened against the booking. See Termination Requests. |
Operational
Section titled “Operational”| Field | Type | Description |
|---|---|---|
bookingTtl |
BookingTtl |
The time-to-live of a tentative booking |
checklist |
Checklist |
The booking’s checklist. See Checklists. |
conversation |
Conversation |
The booking’s guest conversation |
messagingMode |
MessagingModeEnum |
How guest messages are routed for this booking |
channelConnectionStatus |
ChannelConnectionStatusEnum! |
Whether replies can still be relayed to the guest through the booking’s channel connection |
enabledConversation |
Boolean |
Whether messaging is enabled for the booking |
messageThreadEmailAddress |
String |
The email address used for the booking’s message thread |
Key enums
Section titled “Key enums”BookingStatusType: see Booking status for the full value list. CHECKED_IN and
CHECKED_OUT are deprecated in favor of occupancyStatus.
OccupancyStatusType — see Occupancy status for the full value list and descriptions.
ContractTypeEnum
| Value | Description |
|---|---|
SHORT_TERM_LICENCE |
Short-term licence, the default for holiday lets |
AST |
Assured Shorthold Tenancy (UK residential) |
OTHER |
Other contractual arrangement |
StayPurposeEnum
| Value | Description |
|---|---|
HOLIDAY |
Short-term holiday let |
STUDENT |
Student accommodation |
RESIDENTIAL |
Long-term residential let |
BookingRelocationPolicy
| Value | Description |
|---|---|
UNRESTRICTED |
Relocatable, subject to the usual structural checks. The default. |
LOCKED |
Pinned to its current unit; cannot be relocated |
DownPaymentStatusType: COMPLETED, PENDING, REFUNDED
PaymentStatusType: DUE, IN_PROCESS, OVERDUE, SUCCESS
SepaStatusType: COMPLETED, FAILED, PENDING
Note:
search_bookings(see MCP Tools) filters on aPaymentStatusTypewith a broader set of values (includingCANCELED,DISPUTED,EXPIRED,FAILED, andREVERSED), served by a separate search index. ThePaymentStatusTypereturned directly onBooking.paymentStatususes the smaller set above.
Querying bookings
Section titled “Querying bookings”Get a booking by ID
Section titled “Get a booking by ID”query GetBooking($bookingId: ID!) { bookings { booking(bookingId: $bookingId) { id status checkIn checkOut occupancyStatus arrivedAt departedAt confirmationCode contacts { nodes { role contact { id firstName lastName } } } } }}{ "bookingId": "booking-id"}List and filter bookings
Section titled “List and filter bookings”query SearchBookings($filters: BookingsFiltersInput, $first: Int) { bookings { bookings(filters: $filters, first: $first) { totalCount nodes { id status checkIn checkOut occupancyStatus } pageInfo { hasNextPage endCursor } } }}{ "filters": { "status": { "eq": "CONFIRMED" }, "checkIn": { "gte": "2026-09-01T00:00:00Z" } }, "first": 25}This follows the standard pagination pattern used across the
API. For the complete BookingsFiltersInput and BookingsSortInput field reference, see
search_bookings, which documents every supported filter
(status, dates, contacts, vetting, payment, contract, value, and more).
Look up bookings by ID in bulk
Section titled “Look up bookings by ID in bulk”For a lightweight bulk lookup by a known set of IDs, without filters or sorting:
query BookingsByIds($ids: [String!]) { bookings { search(q: { ids: $ids }) { id status } }}{ "ids": ["booking-id-1", "booking-id-2"]}Download a signed contract from the e-signing provider
Section titled “Download a signed contract from the e-signing provider”Each contract carries its DocuSign envelope ID (externalId) and, under esigningEmbed, the coordinates of the
workspace’s DocuSign account. A client serving several workspaces reads them per booking instead of keeping its own
workspace-to-account mapping.
query BookingContracts($bookingId: ID!) { bookings { booking(bookingId: $bookingId) { contracts { externalId status esigningEmbed { environment accountId apiBaseUri } } } }}To fetch the signed documents of a COMPLETED contract, call DocuSign with your own integration, granted access
to the account by its owner:
GET {apiBaseUri}/restapi/v2.1/accounts/{accountId}/envelopes/{externalId}/documents/combined. The API exposes
identifiers only, never Lavanda’s DocuSign credentials. esigningEmbed is null when the workspace has no
e-signing account, and accountId or apiBaseUri is null while it has none recorded. Both always describe the
workspace’s current account, so an envelope sent before the workspace switched account or went live is not
reachable through them.
Creating a booking
Section titled “Creating a booking”mutation CreateBooking($booking: BookingInputType!) { bookings { create(booking: $booking) { booking { id } } }}{ "booking": { "productId": "product-id", "unitId": "unit-id", "checkIn": "2026-09-15T15:00:00Z", "checkOut": "2026-09-20T11:00:00Z", "contacts": [ { "contactId": "contact-id", "role": "LEAD_GUEST" } ] }}Input fields:
| Field | Type | Description |
|---|---|---|
productId |
ID! |
The product to book |
unitId |
ID |
The unit to book. When omitted, a unit is auto-allocated from the product’s active units. |
checkIn |
ISO8601DateTime! |
The check-in date and time |
checkOut |
ISO8601DateTime! |
The check-out date and time |
contacts |
[ContactInputType!]! |
The contacts for the booking |
checklistItems |
[ChecklistItemInputType!] |
Additional checklist items to create alongside the ones generated from the product group’s checklist template. These two sets are not deduplicated. |
Error codes:
| Code | When |
|---|---|
product_not_found_error |
No product matches productId |
product_not_available_for_booking_error |
The product cannot currently be booked |
product_does_not_contain_units_error |
The product has no units to allocate |
product_group_not_found_error |
The product’s parent product group could not be resolved |
unit_not_found_error |
unitId was supplied but does not match a unit |
unit_does_not_belong_to_unit_type_error |
The supplied unit does not belong to the product’s unit type |
find_unit_error |
The unit lookup failed |
no_units_available |
No unit could be allocated for the requested dates |
no_units_allocated_to_pool_error |
No units are allocated to the availability pool |
unit_not_allocated_to_product |
The unit is not allocated to the requested product |
unit_not_available |
The requested unit is not available for the requested dates |
pool_not_found_error |
The availability pool could not be resolved |
crm_contact_not_found_error |
A supplied contact ID does not resolve to a CRM contact |
lead_guest_not_found_error |
No lead guest was found among the supplied contacts |
update_contact_error |
Updating a supplied contact failed |
start_date_range_error / end_date_range_error |
checkIn or checkOut falls outside an allowed range |
invalid_date_error / invalid_date_range_error / date_parsing_error |
The supplied dates are invalid or could not be parsed |
rate_not_found |
No applicable rate could be resolved for the stay |
create_checklist_item_error |
A supplied checklistItems entry could not be created |
checklist_template_read_error |
The product group’s checklist template could not be read |
item_limit_exceeded_error |
Too many checklist items were supplied |
create_booking_error |
The booking could not be created for another reason |
user_not_allowed_error |
The caller lacks permission to create the booking |
Tentative bookings
Section titled “Tentative bookings”Confirm a tentative booking:
mutation ConfirmTentativeBooking($confirmTentativeBooking: ConfirmTentativeBookingInputType!) { bookings { confirmTentativeBooking(confirmTentativeBooking: $confirmTentativeBooking) { booking { id } } }}{ "confirmTentativeBooking": { "bookingId": "booking-id" }}Expire a tentative booking early:
mutation ExpireTentativeBooking($expireTentativeBooking: ExpireTentativeBookingInputType!) { bookings { expireTentativeBooking(expireTentativeBooking: $expireTentativeBooking) { booking { id } } }}{ "expireTentativeBooking": { "bookingId": "booking-id" }}Error codes (shared by both operations): tentative_booking_not_found, booking_not_tentative_error,
booking_expired_error, failed_to_update_booking_status, booking_ttl_not_found, finding_job_error,
deleting_job_error, failed_to_update_booking_ttl, processing_error, user_not_allowed_error, plus
booking_not_expired and failed_to_update_booking_ttl_expiry for expiry only.
Tip:
updateTentativeBookingStatusis the general-purpose version of these two operations, taking an explicitstatus: CONFIRMEDorstatus: TENTATIVE_EXPIRED. PreferconfirmTentativeBookingandexpireTentativeBookingfor their clearer intent.
Recording arrival and departure
Section titled “Recording arrival and departure”Marking a resident arrived or departed stamps arrivedAt / departedAt and updates occupancyStatus. Both default
to the current time; pass at to record a different time. Calling either mutation again once the resident is
already marked arrived (or departed) is a no-op: it returns the booking unchanged and does not update the
timestamp, even if the second call passes a different at.
markArrived refuses to record an arrival before the contract starts. If the arrival (at, or now) or the current
time falls on a day before the booking’s checkIn date, it returns check_in_date_not_reached. Days are counted in
the property’s timezone, so a check-in on the checkIn day itself is always accepted. Neither mutation otherwise
checks the booking’s status or its scheduled dates, so, for example, markDeparted can be called on a booking that
was never marked arrived.
mutation MarkArrived($input: MarkArrivedMutationInput!) { bookings { markArrived(input: $input) { booking { id occupancyStatus checkedInStatus arrivedAt } } }}{ "input": { "bookingId": "booking-id" }}mutation MarkDeparted($input: MarkDepartedMutationInput!) { bookings { markDeparted(input: $input) { booking { id occupancyStatus checkedInStatus departedAt } } }}{ "input": { "bookingId": "booking-id" }}Both input types share these key fields (the description refers to arrival for MarkArrivedMutationInput and
departure for MarkDepartedMutationInput):
| Field | Type | Description |
|---|---|---|
bookingId |
ID! |
The booking whose resident arrived (or departed) |
at |
ISO8601DateTime |
When the resident physically arrived (or departed); defaults to now |
Note: Marking a booking arrived or departed only ever sets
occupancyStatustoCHECKED_INorCHECKED_OUT.NO_SHOWandOVERSTAYare set automatically when a booking misses its check-in or check-out window;AWAYis not currently set by anything.
Error codes: booking_not_found, check_in_date_not_reached (markArrived only),
failed_to_mark_booking_arrived (or failed_to_mark_booking_departed), failed_to_publish_kafka_message,
user_not_allowed_error, validation_error.
Setting scheduled move dates
Section titled “Setting scheduled move dates”setScheduledMoveDates overrides a booking’s planned physical move-in and move-out date and time, independent of
the contract window. Passing null for either field clears the override, reverting that field to the contract
default (see Three layers of dates).
Note: Rescheduling
scheduledMoveInAton a booking currently markedNO_SHOWclears that occupancy status, so the booking is re-evaluated against the new date rather than staying stuck as a no-show.
mutation SetScheduledMoveDates( $bookingId: ID! $scheduledMoveInAt: ISO8601DateTime $scheduledMoveOutAt: ISO8601DateTime) { bookings { setScheduledMoveDates( bookingId: $bookingId scheduledMoveInAt: $scheduledMoveInAt scheduledMoveOutAt: $scheduledMoveOutAt ) { booking { id scheduledMoveInAt scheduledMoveOutAt occupancyStatus } } }}{ "bookingId": "booking-id", "scheduledMoveInAt": "2026-09-15T18:00:00Z", "scheduledMoveOutAt": "2026-09-20T09:00:00Z"}Input fields:
| Field | Type | Description |
|---|---|---|
bookingId |
ID! |
The booking to re-schedule |
scheduledMoveInAt |
ISO8601DateTime |
Planned physical arrival. Omit or pass null to clear the override and revert to the contract default. |
scheduledMoveOutAt |
ISO8601DateTime |
Planned physical departure. Omit or pass null to clear the override and revert to the contract default. |
Error codes:
| Code | When |
|---|---|
booking_not_found |
No booking matches bookingId |
failed_to_set_scheduled_move_dates |
The scheduled move dates could not be saved |
user_not_allowed_error |
The caller lacks permission to set scheduled move dates for this booking |
validation_error |
The input failed structural validation |
Canceling a booking
Section titled “Canceling a booking”Direct cancellation is immediate and is scoped to direct bookings. For a reviewable cancelation workflow with separate submit and approve steps, see Cancelation Requests instead.
mutation CancelBooking($cancelBooking: CancelBookingInputType!) { bookings { cancelBooking(cancelBooking: $cancelBooking) { booking { id } } }}{ "cancelBooking": { "bookingId": "booking-id", "cancellationReason": "Guest requested cancellation" }}Input fields:
| Field | Type | Description |
|---|---|---|
bookingId |
ID! |
The booking to cancel |
cancellationReason |
String |
The reason for cancelling the booking |
Error codes:
| Code | When |
|---|---|
booking_not_found |
No booking matches bookingId |
booking_not_local_direct |
The booking is not a direct booking and cannot be canceled this way |
booking_not_active |
The booking is not in a cancelable state |
internal_booking_cancelation_failed |
The cancellation could not be completed |
user_not_allowed_error |
The caller lacks permission to cancel the booking |
validation_error |
The input failed structural validation |
Moving and splitting a booking
Section titled “Moving and splitting a booking”Note: Both
moveBookingandsplitBookingrun asynchronously. The mutation itself returns immediately with the booking ID(s) once the request is accepted; it does not confirm the move or split has completed. Re-query the booking’saccommodationsto confirm the outcome.
mutation MoveBooking($bookingMove: MoveBookingInputType!) { bookings { moveBooking(bookingMove: $bookingMove) { bookings } }}{ "bookingMove": { "bookingId": "booking-id", "fromUnitId": "unit-id-a", "toUnitId": "unit-id-b", "moveCheckIn": "2026-09-20", "moveCheckOut": "2026-09-25", "moveReason": "Guest requested a quieter unit" }}splitBooking follows the same shape, dividing the stay into segments instead of moving it wholesale:
mutation SplitBooking($bookingSplit: SplitBookingInputType!) { bookings { splitBooking(bookingSplit: $bookingSplit) { bookings } }}{ "bookingSplit": { "bookingId": "booking-id", "splitReason": "Guest requested a room change partway through the stay", "segments": [ { "unitId": "unit-id-a", "checkIn": "2026-09-15", "checkOut": "2026-09-20" }, { "unitId": "unit-id-b", "checkIn": "2026-09-20", "checkOut": "2026-09-25" } ] }}Other booking mutations
Section titled “Other booking mutations”| Mutation | Purpose |
|---|---|
addContactsToBooking |
Adds guest contacts to a booking (up to 10; only one lead guest allowed) |
removeContactFromBooking |
Removes a single contact from a booking |
changeBookingLeadGuest |
Changes the lead guest on a booking |
updateGroupBookingName |
Renames a group booking |
applyDiscount |
Applies a specific coupon-backed discount to a booking |
removeDiscount |
Removes a previously applied discount |
redeemCoupon |
Redeems a coupon by its code against a booking |
addOptionalServices |
Adds one or more optional services to a booking |
updateOptionalServices |
Updates an existing optional service on a booking |
removeOptionalServices |
Removes optional services from a booking |
setRelocationPolicy |
Sets whether a booking may be moved off its current unit (UNRESTRICTED or LOCKED) |
updateBookingTtl |
Updates a tentative booking’s time-to-live expiry |
startChannelCancellation |
Starts a channel cancellation request for a booking on the originating platform |
importBookings |
Bulk-imports a batch of bookings from an external source |
Checklists
Section titled “Checklists”A booking’s checklist tracks operational tasks against it, each with a category, type, status, and an optional guard controlling when it can be transitioned.
query BookingChecklist($bookingId: ID!) { bookings { booking(bookingId: $bookingId) { checklist { id items { nodes { id label category status type isEditable } } } } }}{ "bookingId": "booking-id"}Add items, update a custom item, and transition an item (complete or waive it):
mutation CreateChecklistItems($bookingId: ID!, $items: [ChecklistItemInputType!]!) { bookings { createChecklistItems(bookingId: $bookingId, items: $items) { checklist { id } } }}mutation TransitionChecklistItem($id: ID!, $input: TransitionChecklistItemInputType!) { bookings { transitionChecklistItem(id: $id, input: $input) { checklistItem { id status } } }}{ "id": "checklist-item-id", "input": { "transition": "COMPLETE" }}transition accepts COMPLETE or WAIVE. See the MCP tools below for get_booking_checklist,
create_checklist_items, and update_checklist_items, which cover the checklist surface in full.
MCP Tools
Section titled “MCP Tools”If you are using the Lavanda MCP integration, the following tools are available for working with bookings:
- get_booking - Get detailed booking information by ID
- search_bookings - Search bookings with rich filtering, sorting, and pagination
- update_booking_ttl - Update a tentative booking’s time-to-live
- get_booking_checklist - Get a booking’s checklist
- create_checklist_items - Add checklist items to a booking
- update_checklist_items - Update a booking’s checklist items
See the MCP Tools overview for setup instructions and the full list of available tools.
Webhooks
Section titled “Webhooks”| Event type | When it fires |
|---|---|
v1.booking.created |
A booking is created |
v1.booking.confirmed |
A tentative booking is confirmed |
v1.booking.expired |
A tentative booking expires (or is explicitly expired) |
v1.booking.updated |
A booking is updated |
v1.booking.lead_guest_changed |
A booking’s lead guest changes |
v1.booking.declined |
A booking is declined |
v1.booking.canceled |
A booking is canceled |
v1.booking.terminated |
A booking is terminated |
v1.booking.booking_ttl.updated |
A tentative booking’s time-to-live is updated |
v1.booking.checklist_item.created |
A checklist item is created |
v1.booking.checklist_item.completed |
A checklist item is completed |
v1.booking.checklist_item.waived |
A checklist item is waived |
Cancelation and termination requests emit their own event types, documented on their own pages (see Key Concepts above for links).
Payload shape:
{ "type": "v1.booking.confirmed", "id": "evt_2x...", "timestamp": "2026-05-22T13:00:00Z", "booking": { "id": "booking-id" }, "workspace": { "id": "workspace-id" }}| Field | Type | Description |
|---|---|---|
type |
string |
The event type |
id |
string |
Stable, unique identifier for this event delivery |
timestamp |
string (ISO 8601) |
When the underlying change happened |
booking.id |
string |
The booking the event concerns |
workspace.id |
string |
The workspace that owns the booking |
To resolve any further detail after receiving an event, re-query the booking via the GraphQL API using the
booking.id from the payload. See Webhooks for the general delivery
model and signature verification.
Relationships
Section titled “Relationships”- A booking belongs to a workspace, and is made against a product (see Products), which allocates it to one or more units over time (see Buildings, Unit Types, and Units)
- A booking has one or more contacts (see Contacts), typically originating from a lead (see Leads)
- A booking can have cancelation requests and termination requests (each at most one pending at a time)
- A booking can have a checklist of operational tasks, discounts, and optional services
See Structure & Terms for how these entities fit together across the platform.