Tenancy
Data is organized under organization → property group → property. An organization (what users sign into) anchors exactly one property group — the highest-order data tenant. A property group owns properties: single operated entities like one hotel or venue. Every credential resolves to a property group. SendX-Property-Id to narrow one request to a property in that group.
A property-pinned API key is already narrowed.
Entities
Guest profiles
GET /v1/guests · GET /v1/guests/{id} · reference
A guest profile is one source system’s record of a guest — Mews’ view, Square’s
view — kept exactly as ingested (names, contact details, preferences, tags),
stamped with the integration_id it came from. The same real person appears
once per source that knows them.
Fetch one profile by its Casa Layer ID (GET /v1/guests/{id}). A miss is
404. Look up by PMS guest ID with source_id + integration_id on
GET /v1/guests. That path returns a one-page list: one row, or data: []
when nothing matches. Some source systems do not expose a stable guest
source_id. List integration IDs with GET /v1/integrations.
Master profiles
GET /v1/master-profiles · searchable by name, email, phone, exact sub-profile email, or Casa Layer reservation ID
The golden record. Identity resolution merges guest profiles across source
systems and properties into one master profile per real guest, with
per-attribute provenance (attribute_sources records which system supplied
each canonical field) and the full list of merged member sub-profiles
(guest_profiles plus guest_profile_ids). Use email for an exact
sub-profile email lookup.
reservation_id is the Casa Layer reservation UUID (reservations.id), not
the PMS reservation source_id. Resolve the PMS ID on
GET /v1/reservations first, then send the returned id. A value that is
not a UUID matches nothing. When you want “the guest”, not “what one system
knows about the guest”, read these.
Reservations
GET /v1/reservations · GET /v1/reservations/{id} · filter by status, stay window, channel, guest, or source_id + integration_id
Stays and bookings, linked to the guest profile that made them. Fetch one
reservation by its Casa Layer ID (GET /v1/reservations/{id}). A miss is
404. Search by the source system’s reservation ID with source_id and the
integration_id that owns it. That search is a keyset-paginated list. List
integration IDs with GET /v1/integrations. Statuses are normalized to a
canonical lifecycle (pending, confirmed, in_progress, completed,
cancelled, declined, no_show) and channels to canonical categories
(direct, ota, …) — the original vendor values remain in source_payload.
Transactions
GET /v1/transactions · filter by guest, reservation, consumption date, type
Revenue lines shaped like Pace Transactions V2 — one row per source order item,
with net_revenue and gross_revenue, optional reservation_id, and a
canonical type (e.g. space, product). Guest spend is the sum
of linked transactions.
Consents
GET /v1/consents · GET /v1/consents/{id} · filter by contact value/method, purpose, status, integration, observing guest
Contact-grain marketing and compliance observations — one row per decisive source
signal (granted, withdrawn, denied) for a contact method + value and purpose
(email ≠ SMS). Default-unknown: no row means unknown / not eligible; connectors do
not store coverage rows for vendor silence. Effective eligibility within a property
group is the most restrictive status among matching stored observations.
Actions
GET /v1/actions
Tracked guest actions — purchases, visits, requests — newest first, linked to
a guest profile and property. Shape varies by source (name, type,
status, requested_at, completed_at).
Guest event log
GET /v1/events · timeline or latest mode · filter by entity, guest profile, or master profile
The append-only history of everything Casa Layer has observed: every change to every
entity, in order, forever. timeline mode is keyset-paginated change history.
latest mode returns one page — the latest delta slice per entity (next_cursor
is null). The rollup alias is kept for compatibility and behaves the same.
Filter to one sub-profile with guest_profile_id, or send master_profile_id
to read history across clustered member sub-profiles. The event log does not
accept a PMS source_id. Resolve the guest first, then send the Casa Layer
ID. This is the replayable source of truth behind the canonical tables. See
Retrieving the guest event log.
Reviews
GET /v1/reviews · GET /v1/reviews/summary
Guest reviews from every connected channel (Booking.com, Google, …) with
ratings, tags, and host responses. The summary endpoint aggregates them —
average rating, rating distribution, per-channel breakdown, top
positive/negative tags — for a scope and date window.
Loyalty
GET /v1/loyalty-programs · GET /v1/loyalty-members
Loyalty program definitions and their memberships. Member search joins each
membership with its guest (name, email) and program, ordered by points —
filter by tier, program, or free-text guest match.
Channels & spaces
GET /v1/channels · GET /v1/spaces
Reference resources: the booking channels reservations and reviews arrive
through, and the bookable spaces (inventory types) they concern.
Integrations
GET /v1/integrations
The mapping roster for your scope. Each row is one source system mapped to a
property. id is the integration_id you send with source_id when you look
up a guest or reservation. Public credentials (read:properties) see a thin
row: id, provider, name, property_id, status, source_ref. The
response is the full roster — it is not cursor-paginated. Connection
credentials stay session-only.
Properties
GET /v1/properties
The roster of properties in your group. The response is the full set
({ "data": [ … ] }) — it is not cursor-paginated. Use a property id as
X-Property-Id to drill one request down.
Tables
GET /v1/tables · GET /v1/tables/{id} · GET /v1/tables/{id}/members · POST /v1/tables/preview · GET /v1/tables/{id}/filters · POST /v1/tables/{id}/preview · GET /v1/tables/{id}/runs · GET /v1/tables/{id}/destinations
Group-scoped ops containers of master or guest members — static curation or
lightweight attribute filters. Each table has a type: static (manual
add/remove) or dynamic (membership from saved filters, updated when you
click Save). member_type (master or guest) is fixed at create and never
mixed within one table.
Member responses use profile directory projections plus guest_profile_id,
master_profile_id, and consents. id is the membership key. On a
guest table it matches guest_profile_id. On a clustered master row it
matches master_profile_id and guest_profile_id is null — load member
guests from GET /v1/master-profiles/{id}. Member rows can still carry
kind (clustered or singleton) — that field describes the profile
row, not the table’s type. List, member, and preview routes use
offset pagination, not keyset cursors.
MCP read tools: tables_list, table_get, table_members (scope
read:tables). Writes require write:tables on REST. Filter tooling:
POST /v1/tables/preview tests an ad-hoc filter without saving it;
/{id}/filters reads the saved filter, /{id}/preview previews its
matches, /{id}/runs audits refreshes, and /{id}/destinations shows ESP
bindings with consent-filter guidance. Tables are not
marketing segments — campaign audiences live in downstream ESPs. See
Creating a table of guests who have provided marketing consent.