Guest identity, duplicates and consents
Questi contenuti non sono ancora disponibili nella tua lingua.
Guests are workspace identities. Contact details are not unique: people may share a name, e-mail address or phone number. The Guests screen supports search, profile editing, stay history, duplicate review, consent evidence and owning-property reassignment. ADR 0045 records the identity rules.
Review duplicates
Section titled “Review duplicates”Open Guests and choose Duplicates, or open a guest profile’s duplicate panel. Each candidate explains its matching e-mail or phone, with matching names as additional context. A name alone never proposes a pair. Stronger matches appear first. Review both profiles before deciding. “Not a duplicate” remembers the pair and writes an audit record; reload does not propose that pair again. “Show dismissed” includes remembered pairs and offers an audited undo. Repeating the current dismissal state creates no extra audit entry.
Contacts shared by more than five live profiles appear once as a shared-contact group. Open the group to review its paginated members. They are not expanded into every possible pair. Normalized keys are stored and indexed; the profile panel uses equality lookups.
The core does not collect birth dates, document numbers or country-specific legal identification for this workflow. A matching contact is evidence to review, not proof that two people are the same.
Merge two identities
Section titled “Merge two identities”An administrator with guests.merge opens the comparison, chooses which guest survives,
and selects the source of each contact field. Confirming checks the versions of both
guests. The comparison labels the current Survives and Absorbed identities, shows their
owning properties and reservation counts, and offers each field’s actual values. Review
the latest consent decision for every purpose on each identity, including any withdrawal
warning, and the final summary before confirming. A conflict requires reloading and
reviewing the new values before trying again.
The survivor receives the chosen details and the live reservation references. Folios,
Channex booking links and message threads remain attached to their reservations, so
those reservations’ guest identity now resolves to the survivor. Immutable snapshots and
historical records are preserved. The absorbed guest remains readable with a pointer to
the final visible survivor and retains its own read-only consent history. Its former URL
does not become a 404. The survivor’s “Merged from” links open absorbed profiles and their
history. Lists and search exclude absorbed profiles by default; API clients can request
include_merged=true when they need historical identities.
Each moved reservation receives a new version and its ordinary update audit/event in the same transaction. Clients holding its old ETag must refetch before changing it.
A manually merged survivor is operator-owned and remains editable even when it has OTA reservations. Later OTA revisions preserve the chosen identity and update booking facts. Their latest contact snapshot is stored separately on the reservation. When details differ, the profile shows the channel, revision time and differing fields. “Apply” uses the ordinary audited guest edit with the current version; it never automatically replaces the identity.
The current reservation model has one booker guest identity, and a split folio may name a guest as its payer. Occupant counts do not create separate guest identity links; registration of individual occupants remains a separate product capability. The merge covers every live guest reference in the current model: it moves folio payers to the survivor too, and a merged identity cannot be chosen as a payer again.
Reservation creates and guest changes may use an absorbed guest ID when the entire
pointer chain is visible to the caller. They resolve to the live identity and return
that guest in the successful response. A hidden or missing intermediate profile returns
guest.not_found before the reservation changes; an old alias cannot widen property access.
Merge never crosses a workspace or organization. Property-restricted members cannot merge because an identity may be linked to bookings at properties hidden from them.
Record consent evidence
Section titled “Record consent evidence”The profile offers marketing e-mail, marketing phone and marketing SMS purposes.
A member with guests.consents can record granted or withdrawn, with a source and an
optional note. Current decisions are shown per purpose independently of history pages.
History is newest first and shows the actor’s display name, source, note and time in the
user’s time zone. A later entry does not replace or delete earlier evidence. Server time
is authoritative.
Consents remain attached to the identity that provided them. Merging never copies or
combines them. A withdrawal on an absorbed identity remains in that identity’s history;
it does not silently change the survivor’s independent history. An absorbed profile accepts
no writes: consent, dismissal, undo, merge, edits and ownership changes answer
409 guest.absorbed with a final survivor pointer. Open that profile before recording a
new decision. Its tombstone page has no write actions or booking call to action. This panel records
operator evidence and does not authorize a marketing delivery or apply national rules.
Correct owning property
Section titled “Correct owning property”An unrestricted administrator with guests.reassign can change a profile’s owning
property to another property in the same workspace. The operation checks the guest
version, saves the new owner and records audit/event history atomically. This can change
visibility for property-restricted members. Legacy unowned guests are not automatically
backfilled; an administrator may explicitly assign their owner.
Permissions and concurrency
Section titled “Permissions and concurrency”guests.read reads profiles, duplicates and consent history. guests.manage edits
contacts and dismisses candidates. The new grants appear in the custom-role editor:
guests.merge and guests.reassign default to administrators; guests.consents defaults
to administrators, front desk and revenue managers. All operations still require live
workspace membership and their declared property scope.
Guest transitions require a strong guest If-Match. Merge also takes the absorbed
guest’s version; dismissal checks both profile versions without changing them. Merge,
consent recording and ownership reassignment return the resulting guest version. A stale version answers 412 guest.version_mismatch; clients must review current data before resubmitting. The API,
OpenAPI and generated SDK expose the same workflow; use the guests operation module
and @guestcraft/react/query/guests factories. Ordinary identity/reference writes take a
shared workspace gate; merge alone takes it exclusively, so writes at different properties
can proceed concurrently. Property locks precede that gate and row locks follow it.
Public operations
Section titled “Public operations”All paths below are under /api/v1; the workspace is selected with
GuestCraft-Workspace-Id.
| Operation | Permission | Result |
|---|---|---|
GET /guests?include_merged=true |
guests.read |
Include historical absorbed profiles (excluded by default) |
GET /guests/duplicates |
guests.read |
Cursor page of workspace candidates and reasons |
GET /guests/{id}/duplicates |
guests.read |
Cursor page restricted to that profile |
PUT /guests/{id}/duplicate_dismissals/{other_id} |
guests.manage |
Remembered, audited pair dismissal; both versions checked |
DELETE /guests/{id}/duplicate_dismissals/{other_id} |
guests.manage |
Audited undo; both versions checked |
GET /guests/shared_contacts |
guests.read |
Paged shared-contact groups; profile subresource also available |
GET /guests/shared_contact_guests |
guests.read |
Complete paged membership for a shared key |
GET /guests/{id}/merges |
guests.read |
Paged visible absorbed ancestry |
GET /guests/{id}/contact_notices |
guests.read |
Newest-first eligible OTA field snapshots per reservation |
PUT /guests/{id}/contact_notice_dismissals/{reservation_id}/{field} |
guests.manage |
Keep the current field and remember the dismissed snapshot value; guest If-Match required |
POST /guests/{id}/merge |
guests.merge, unrestricted properties |
Survivor, its new ETag, and preserved absorbed identity |
GET /guests/{id}/consents |
guests.read |
Cursor page of the complete consent history |
GET /guests/{id}/consents/current |
guests.read |
Latest decision for each purpose, independent of history paging |
POST /guests/{id}/consents |
guests.consents |
New immutable evidence entry and updated guest ETag |
PUT /guests/{id}/ownership |
guests.reassign |
Guest with corrected owner and new ETag |
The existing guest read/edit and reservation-history operations remain available.
Duplicate reads filter dismissals before pagination; include_dismissed=true also returns
remembered pairs. Duplicate dismissal supplies other_version in its body; undo supplies
it in the query. Both use the path guest’s strong If-Match. Same-identity or unrelated dismissal pairs answer
422 guest.pair_invalid. Merge supplies absorbed_id,
absorbed_version, and a fields choice (survivor or absorbed) for every contact
field (omitted choices retain the survivor). Ownership supplies origin_property_id. Consent supplies purpose, status,
source and optional note. The OpenAPI operation descriptions define exact validation
and problem responses.
Retention, erasure and planned capabilities
Section titled “Retention, erasure and planned capabilities”Merge preserves data; it is not erasure. Retention periods, erasure, access exports and legal holds are described in guest data rights: an erasure covers the live profile and every profile merged into it, and an erased profile keeps its identifier and merge pointers. Legal identification and country compliance documents remain country-pack capabilities. Groups, online check-in, country compliance and marketing campaign delivery remain planned.
OTA notices say which channel sent the contact details and when. They contain only differing
fields from snapshots later than that field’s last review, newest first. Apply and ordinary
contact edits review only changed fields; notes edits do not clear unrelated notices. Keep
current dismisses one exact value for one field, audited without putting contact values in
the audit log. The same value remains suppressed on future revisions and other reservations;
a different later value can still be reviewed. Dismissal sends the snapshot revision id and
expected value; a changed snapshot returns 409 guest.contact_notice_changed for reload.