VRPlatformVRPlatform
Build a Product UI

Listings & Ownership

Build listing, ownership, contact, and owner-access workflows

Mental Model

A listing is the shared property context for ownership, reservations, fees, transactions, statements, and reporting. Ownership periods define who owns it over a date range. Contacts provide owner, vendor, payout, tax, and portal identity.

Resources and Lifecycle

Listings keep platform identity even when PMS references, status, groups, or owners change. Inactive listings and contacts remain in accounting history.

Ownership periods combine a listing, date range, business model, owner members and splits, reserve behavior, and optional setListingInactive. Periods cannot overlap. A changed owner constellation or allocation creates a new period.

Owner access is separate from contact identity. Invitations and viewer changes can affect an external identity provider and send notifications.

Read Model

Render returned listing status, active ownership, fee periods, parent and children, upcoming deactivation, and issues[]. These fields are the server's setup view; do not rebuild completeness queries in the client.

Keep inactive entities available when rendering history, but exclude them from normal new-entry selectors.

Decision Table

DecisionRule
Business modelmanaged, co_host, or co_host_airbnb
End dateNull means ongoing; start must precede a non-null end
MembersOne or more unique owner contacts unless inactive period
SplitsExplicit plus distributed omitted values form full ownership
DeactivationsetListingInactive=true; do not collect owner members
Overlap defaultonConflict=error
Remove locked historyOffer archive only when error context recommends it
Remove last periodDefaults to onLast=extendPrevious; send onLast=none unless the extension is confirmed
Payout accountAccounting account reference, never bank credentials

Conflict strategies are error, updateExisting, and adjustInsertingItem. Explain that the latter two can change a neighboring stored period or the proposed range.

The onLast=extendPrevious default stretches the previous period over the removed range, so keep it only when the user has confirmed that outcome; otherwise pass onLast=none.

Contacts and Owner Access

Contacts are owners or vendors. Owners can join ownership periods and receive statements or portal access; vendors are normally selected on expenses and recurring expense templates.

Invitations require an owner contact with an email. Admin and viewer access are mutually exclusive for one owner/user pair; remove the existing role before inviting the other.

Invites resolve email against the global platform identity before adding regional owner access. A user whose former team membership was removed can be invited into another region with the same email; the existing identity is reused. If a non-owner team membership still exists in any region, the owner invite remains blocked. Legacy identity-provider IDs are not part of the user API or copied into another region.

Editability

Ownership dates and listing groups can change journal attribution across many resources. Books closing, statement periods, statement attachment, or locked ownership history can prevent moving or shortening a period.

An inactive period rejects owner-side postings in that range. Manager-side records can retain listing attribution when the operation permits it.

Invitations, viewer creation, reinvites, and access removal are external identity workflows. Do not present them as ordinary reversible contact edits.

Preview and Preflight

Dry-run listing, ownership-period, group, contact, and supported delete/archive mutations when their generated operations declare support. Always preflight an ownership range or parent change because one edit can affect reservations, fees, statements, and journal attribution outside the visible row.

Mutation Recipe

  1. Load listing setup state, ownership periods, contacts, and returned issues.
  2. Validate date ordering, unique owners, splits, and business model locally.
  3. Select and explain an overlap strategy.
  4. Render current locks and any suggested archive outcome.
  5. Dry-run the complete proposed listing or period mutation.
  6. Show every adjusted neighboring period returned by the API.
  7. Confirm and apply the same payload.
  8. Re-read listing setup and affected periods.

Failure and Recovery

On overlap, keep the proposed dates and let the user choose a documented strategy. When a lock blocks the change, show the structured lock context and the first open date, and offer archive only if the error context returns suggestedOnLocked: "archive". After a concurrent edit, reload all periods before offering conflict resolution again.

Common Recipes

Mid-month ownership change

End the current period and create the new owner constellation with a boundary that does not overlap. Expect separate statements for the same listing and month when both periods contain activity.

For example, this preflight starts a new ownership period on July 15 and lets the API trim the overlapping current period:

POST /listings/ownership-periods?dryRun=true
Content-Type: application/json

{
  "listingId": "11111111-1111-4111-8111-111111111111",
  "startAt": "2026-07-15",
  "endAt": null,
  "members": [
    {
      "contactId": "33333333-3333-4333-8333-333333333333",
      "split": 60000
    },
    {
      "contactId": "44444444-4444-4444-8444-444444444444",
      "split": 40000
    }
  ],
  "onConflict": "updateExisting"
}

Deactivate a listing

Create or update the relevant ownership period with setListingInactive=true. Do not delete historical owners or prior periods.

PUT /listings/ownership-periods/{ownershipPeriodId}?dryRun=true
Content-Type: application/json

{
  "setListingInactive": true
}

Webhook Reconciliation

listing.changed invalidates the canonical listing after creation, public configuration or hierarchy changes, archive/reactivation, and deletion. Compare resourceVersion and fetch href; a deletion tombstone may return 404. Ownership-period changes emit only when the canonical listing response changes.

API Reference

On this page