VRPlatformVRPlatform
Build a Product UI

Reservations

Build booking, financial-line, adjustment, and mapping workflows

Mental Model

A reservation connects booking identity and stay context to accounts receivable, revenue, fees, deposits, adjustments, and owner statements. The API constructs accounting output; the client renders it.

Resources and Lifecycle

Reservations contain listing, guest, stay dates, source identity, booking status, payment lines, adjustments, and calculated financial output.

Writes accept the booking statuses booked, cancelled, canceled, inquiry, and inactive; both cancellation spellings are equivalent on write. Reads always return booked, canceled, or inactive. Booking status and generalLedgerStatus=active|inactive are separate. The normal reservation update (PUT /reservations/{id}) changes booking status; the dedicated status update (PUT /reservations/{id}/status) activates or inactivates reservation journal entries.

Read Model

Render returned financial lines, resolved accounts, posting dates, totals, paid state, locks, and issues. Do not recreate cancellation, deferred revenue, fee calculation, or journal generation in the client.

Use returned source and connection state to decide which synced fields the user can edit.

Decision Table

Context changeRecalculate or validate
Booking status (booked, cancelled/canceled, inquiry, inactive)Active financials, adjustments, and journal consequences
generalLedgerStatusJournal activity without changing booking status
Listing or stay datesOwnership, recognition, fees, and posting dates
Channel or line typeLine mapping and recognition override
Adjustment partyOwner-period eligibility and locks
Recurring fee adjustmentFee posting accounts and metadata
generalLedgerPostingAtThe adjustment's independent journal date

Adjustments and Posting Dates

An adjustment can specify a line type or account, amount, description, owners|manager party, optional recurring fee, and optional generalLedgerPostingAt.

Owner adjustments participate in ownership and statement locks, while manager adjustments normally avoid owner-period locking. A separate open posting date is required when a new owner adjustment would otherwise reuse a locked reservation A/R date. Use returned date previews rather than assuming stay, cancellation, or A/R date.

For adjustment creation, either provide a concrete generalLedgerPostingAt or set onLocked=nextOpen. The default onLocked=error rejects a locked natural posting date. nextOpen keeps the natural date when it is open; otherwise it resolves and persists the earliest date allowed by books closing and statement-period locks. It does not bypass journal locking, and it cannot be combined with an explicit posting date.

The dry-run response includes the resolved concrete adjustments[].generalLedgerPostingAt without saving the adjustment. The policy applies only when creating an adjustment; adjustment updates continue to require an explicit posting date when moving the line.

Line Mappings and Revenue

Payment-line mappings translate PMS or channel line types into accounts and can override recognition. Recognition can use check-in, check-out, booked-at, or pro-rata dates. Pro-rata can cross months and ownership periods.

For a reservation sourced from a child in a listing group, journal entries keep the child listing as their source and resolve ownership through the group parent. This includes deferred-revenue legs and rebalances. A missing-ownership issue is returned only when neither the stored period nor an effective parent period covers the posting date.

To deliberately exclude a line type from journal posting, create or update its mapping with accountId: null. Use a channel mapping with accountId: null to exclude only that booking channel. Mapping status=excluded and reservation line isExcluded=true are derived read-only results; omitting a line from a reservation payload is not the exclusion control.

Editability

Reservation changes can be blocked by books closing, statement periods, statement attachments, inactive ownership, or source ownership of synced fields. Use the most specific entity or adjustment lock.

An adjustment with an independent open posting date can remain editable while the reservation's owner-side A/R posting is locked. Updating or deleting an adjustment is blocked when its entries are statement-attached or in closed books.

Preview and Preflight

Create, update, batch, booking/accounting status, removal, and adjustment mutations expose dry run where the generated OpenAPI declares the dryRun parameter. Journal regeneration and line-mapping changes intentionally skip generic dry run because they require consequence-oriented results.

Recalculate financial previews when channel, line type, mapping, stay dates, recognition settings, party, fee, or posting date changes.

Mutation Recipe

  1. Load the reservation, financial output, mappings, and returned locks.
  2. Apply source-editability and deterministic status rules.
  3. Recalculate affected account and posting-date previews.
  4. Add an independent adjustment posting date when required.
  5. Dry-run the complete reservation or adjustment payload.
  6. Render structured lock and mapping issues.
  7. Confirm and apply.
  8. Re-read the reservation and render returned accounting output.

Failure and Recovery

A missing mapping means the user needs to configure the exact source line type. Locked owner history calls for showing the relevant period, statement, or first open date rather than silently changing the adjustment to manager. After a source sync or concurrent mutation, reload before retrying.

Common Recipes

Cancel a paid reservation

Update booking status through the reservation mutation, then render returned issues and adjustments. Do not locally synthesize refund journals.

PUT /reservations/{reservationId}?dryRun=true
Content-Type: application/json

{
  "status": "canceled",
  "cancelledAt": "2026-07-19"
}

Post a late owner adjustment

Choose owners, create with onLocked=nextOpen&dryRun=true, inspect the returned posting date and financial lines, then repeat without dryRun to apply. Use an explicit generalLedgerPostingAt instead when the posting date is a user decision.

POST /reservations/{reservationId}/adjustments?onLocked=nextOpen&dryRun=true
Content-Type: application/json

{
  "type": "lateFee",
  "amount": 2500,
  "description": "Late owner charge",
  "party": "owners"
}

Webhook Reconciliation

reservation.changed is emitted after a committed public aggregate change and after required journal or payment effects finish. No-ops, dry runs, rollbacks, and journal-only work that leaves the public response unchanged do not emit. The compact body contains no guest, stay, amount, payment, source, or line data; compare resourceVersion and fetch href.

API Reference

On this page