Salta ai contenuti

Roles and property access

Questi contenuti non sono ancora disponibili nella tua lingua.

Open Settings → Role permissions in a workspace to inspect the permission matrix. Built-in roles are fixed. Select one and choose Duplicate to use its grants as the starting point for a custom role, or create a role from scratch. The role name is unique in that workspace. An unused custom role can be deleted; a role assigned to any member cannot. A custom role cannot take a built-in role’s code or its English catalog name, however it is spelled: “ADMIN”, “Revenue-manager” and “FRONT-DESK” are refused with team.invalid on /name. Former translated names are ordinary custom-role names; existing roles retain their IDs and grants.

Open Settings → Users and roles to assign a role and choose All properties or Selected properties. Select at least one property and save. The member’s next request uses the new role and property set; a reload shows the saved choice. The invitation form also selects role and property access before issuing the link. All properties is the default; a selected invitation grants only those properties from its first accepted request. Organization owners and administrators inherit full access.

Permissions describe individual operations, such as reservations.cancel or folios.refund and folios.approve_open_balance. Granting folios.post does not grant refunds, reversals or open-balance checkout approval. A member limited to some properties can use a permission only at those properties. Team management, workspace audit, Channex and property creation require unrestricted property access. Each catalog entry declares its scope, property or workspace, and the table in ADR 0036 lists what a selected-property member gets for each code. An empty selection grants nothing. The guest directory includes guests created in an allowed property and guests with a reservation there. A guest shared by two properties is visible in both. For a new guest created by a member limited to several properties, the first selected property is recorded as the origin until a reservation links the guest elsewhere.

API clients use the live session, GuestCraft-Workspace-Id, and the existing same-origin write policy. GET /roles reads the catalog; GET/POST /roles/custom lists and creates workspace roles; GET/PUT/DELETE /roles/custom/{role_id} addresses one role; and GET/PUT /members/{member_id}/access addresses one member’s role and property access. Team resources select the workspace with the canonical header; deprecated workspace_id query/body aliases must match it. POST /roles/custom returns 201 with Location and a strong ETag; item GETs return ETag; item PUTs and DELETE require If-Match and reject stale values with 412. Delete returns 204. The SDK exposes team.customRoles, createRole, getRole, updateRole, deleteRole, getAccess, changeAccess, getSignInLock and unlockSignIn; React Query includes their generated options. GET/DELETE /members/{member_id}/sign_in_lock reads and lifts a member’s lock of failed sign-ins (team.manage, which includes a manager’s own lock from an earlier session; DELETE takes the GET’s strong If-Match, answers 400 request.invalid without it, and is audited as team.sign_in_unlocked). The lock itself is audited as team.sign_in_locked. Invitation creation accepts nullable property_ids (omit or null for all). Input uses stable permission codes and canonical property/role IDs. Invalid team bodies return team.invalid (422), while invalid path/header/query syntax returns request.invalid (400); a case-insensitive duplicate name returns team.duplicate_role; a referenced role returns team.role_in_use; removing the last manager returns team.last_admin.

When adding an operation, choose a catalog permission, check it with can at the domain boundary and pass the property ID where applicable. A new code must declare its scope; a workspace code also declares restricted: "filtered" (its operations return only the member’s properties’ rows) or "denied". A read that spans every property the caller may reach uses canAcrossProperties with a property code and relies on the unit of work’s property scope. Add matching English labels and descriptions, UI visibility and a test for built-in compatibility plus custom-role denial. Property-linked tables need a restrictive RLS policy or a documented parent-policy path. See ADR 0036.

The catalog in core/tenancy declares each capability and its scope. Custom roles select them independently; grant each screen’s read permissions as well as its writes:

Area Permission codes
Properties and room setup properties.read, properties.configure, inventory.read, inventory.configure
Guests and reservations guests.read, guests.manage, guests.merge, guests.consents, guests.reassign, reservations.read, reservations.create, reservations.modify, reservations.cancel, reservations.override_price, reservations.rerate
Planning protection reservations.set_do_not_move (set or clear a reservation room’s Do not move flag)
Stays and housekeeping stays.check_in, stays.check_out, stays.override_readiness, housekeeping.update, housekeeping.assign, housekeeping.configure
Rates rates.read, rates.edit, rates.configure_plans
Night audit and cash drawer night_audits.run, night_audits.configure, cash_shifts.read, cash_shifts.open, cash_shifts.close, cash_shifts.configure
Folio folios.read, folios.post (charges), folios.post_payment, folios.refund, folios.correct (reversals), folios.rerate, folios.split, folios.transfer, folios.configure_extras, folios.credits_due, folios.approve_open_balance
Online payments payments.configure (connect the workspace’s provider account; browser session only, unrestricted property access, administrators by default), payments.collect (payment links, saved-card charges, damage-hold capture and release; administrators, front desk and accounting), payments.refund (refunds through the provider; administrators and accounting)
Policies policies.read, policies.configure, policies.prepayments, policies.simulate_cancellation, policies.override_cancellation, policies.no_show, policies.undo_no_show, policies.waive_no_show, policies.manage_guarantee, policies.waive_guarantee
Physical rooms blocks.read, blocks.manage_ooo, blocks.manage_oos, maintenance.read, maintenance.manage
Channex and Messages channex.view_health, channex.configure, channex.manage_account_mode, messages.read, messages.send, messages.configure
Reports, team and integrations reports.view, team.manage, audit.view, api_keys.manage, webhooks.manage, events.read, oauth_applications.manage

Planning moves, splits and resizing require reservations.modify; in-house changes additionally require stays.check_in. Setting or clearing Do not move independently requires reservations.set_do_not_move. A protected movement requires an explicit acknowledgement, even when the actor can change the flag. Undo requires current reservation modification and, in house, check-in access. Restoring the receipt’s frozen sale does not require a new price-override grant.

Cancellation still requires reservations.cancel; cancellation overrides additionally require policies.override_cancellation. Recording a waived guarantee requires both policies.manage_guarantee and policies.waive_guarantee. Check-out still requires stays.check_out; an owed-balance approval additionally requires folios.approve_open_balance. Guest resource edits require guests.manage. Consent evidence uses guests.consents (administrators, front desk and revenue managers by default). Merge and owning-property reassignment use guests.merge and guests.reassign (administrators by default); both require unrestricted property access. See guests. Erasure, access exports and legal holds use guests.erase, guests.export and guests.legal_hold (administrators by default), require unrestricted property access and a browser session, and are never granted to API keys; retention settings use workspaces.configure. See guest data rights.

Reading a reservation’s online payments, a payment link or a provider payment requires folios.read; the payments-due list follows policies.prepayments, amounts included. A cash settlement requires folios.post_payment to take cash and folios.refund to give it back. See online payments.

events.read reads the events API and Settings → Events; events name objects of every property, so it is refused to members (and API keys) limited to selected properties.

oauth_applications.manage lists and revokes the OAuth applications every member authorized in the workspace (Settings → Authorized applications, administrators by default). It is browser-only and refused to members limited to selected properties; no application or key can hold it. Authorizing an application for oneself on the consent page needs no permission: the application never gets more than the member holds. See OAuth applications.

Block type conversion needs both the original and destination type’s manage grant. Ending or removing a block requires its actual type’s grant. Maintenance changes do not grant housekeeping updates. PostgreSQL restricts property-bearing rows and folio children. Invitation authority and last-manager guards recheck effective unrestricted grants inside the serialized team transaction.

A dedicated financial operation returns its complete authorized result, including exact amounts, when its own grant permits it. General reservation views still require folios.read to expose money. For example, policies.prepayments and folios.credits_due work independently of generic folio reads; payment/configuration responses retain their documented money fields. ARI health answers Channex’s price limits only with rates.read for the property; channex.view_health alone gives the rest of health. The front desk’s deposits_due follows policies.prepayments too, amounts included.

The web desk requests only what the member may read. Without properties.read, the shell’s property switcher and the Channels screen read no property list, and Channels names the mapped properties by their IDs; without inventory.read, it shows no room type mapping. Without rates.read, a reservation’s room does not name its rate plan and the booking form offers no quote. Such a member can book only room types without an active rate plan, at a manual price: the API requires a rate plan for a room type that has one.

team.manage grants administration only within the actor’s current effective permissions. It does not grant additional operational capabilities. A supervisor cannot create/update a role beyond that ceiling, assign a broader custom or built-in role, invite someone with such a role, or expand their own access. Organization owners/admins keep full rights. Invitation acceptance rechecks the issuer and current target role under the same team lock.

Use GuestCraft-Workspace-Id on all team requests except acceptance and the public catalog. Deprecated workspace aliases must match it. POST /roles/custom returns CustomRole and a Location identifying the same representation. Role permission arrays have a canonical order, so reordering a grant set preserves both its representation and strong validator. List returns {data,next_cursor,grantable_permissions,grantable_builtin_roles}. Follow cursor with limit (1–100). Member pages expose independent next_cursor and invitations_next_cursor; pass the latter as invitation_cursor. Role/access item operations and legacy member role/removal POSTs use strong If-Match. Access PUT returns a fresh ETag. Inherited organization administration participates in the access representation and its validator. Invalid team bodies return 422; missing custom roles return team.role_not_found (404).

Audit entries expose safe permission/property deltas and previous/next role ids. properties.read protects item and list reads. Room readiness belongs to inventory.read, and so do reading housekeeping tasks, generated days and settings; the ineffective housekeeping.read code has been removed. inventory.configure also permits back-dated arrivals. A folio posting, correction, refund or re-rate answers the full folio only to a caller that also holds folios.read for the property; any other caller receives a FolioAcknowledgement with the folio’s identifiers only (ADR 0036, 2026-10-30 amendment).

PostgreSQL requires explicit app.property_ids='*' for unrestricted access. Missing/empty context grants no property data. Selected contexts cannot modify access-control tables or read workspace-wide audit/events, while still appending operational audit/event writes.