Door & Gate Access
Core Platformdoor_access_auto_messagesDoor & Gate AccessManages the Door & Gate Access automated per-user messaging rules — facility-level rules that automatically set or clear a user's mobile-app message based on their synced membership status, person type, tags, or whether the app has any doors to show.
Manual per-user messages (set via door_access_manage_users) and decoupled/suppressed users are never overwritten by automation.
This tool changes messages only; it never changes regular rules, permanent grants, or Access Time Windows.
Actions:
get— the current config: { enabled, rules: [{ id, enabled, match: { field membershipStatus|type|tag|doorVisibility, values[] }, message: { title, text, severity info|warning|critical, link } }] }. For doorVisibility usenone(no doors visible) orsome(at least one visible door).update— save the config (configobject, full replace — call get first and send back the whole modified document). Saving immediately queues a BACKGROUND sweep that re-evaluates every User Access row at the facility; the response confirms { sweep: { status: 'queued' } }.sweep_status— progress of that background sweep: { status queued|running|done|error, startedAt, finishedAt, usersScanned, usersUpdated, startedBy, error }. Poll this after an update to confirm the sweep finished.
Parameters
| Name | Type | Description |
|---|---|---|
action* | "get" | "update" | "sweep_status" | `get` = read config; `update` = save config + queue re-evaluation sweep; `sweep_status` = background sweep progress. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
config | object | update: the full config { enabled, rules: [{ id, enabled, match: { field, values }, message: { title, text, severity, link } }] }. Full replace — get the current config first. |
door_access_configure_doorDoor & Gate AccessConfigures a Door & Gate Access (DGA) door controller: safety, geofence, and device-side settings. Door authorization is configured centrally with Access Policies. Only the fields you supply are changed; everything else is left untouched.
Configurable fields:
blockAllAccess— explicit door kill switch. When true it denies member access before Access Policies, permanent grants, and all time windows.geofenceOverride— per-door geofence override (enabled, center {lat,lng}, radiusMeters, accuracyBufferMeters...). Passnullto clear.icon— door | door-sliding | door-double | garage | gate-barrier | pedestrian | security | office | delivery | lockerholdTimeSeconds— relay hold time on unlock, 1-30 secondsmaintenanceMode— off | force-open (relay latched open) | force-closed (locked; only admin override unlock works)doorLocation— free-text physical location label, max 64 chars; empty string clearsplayNotificationSoundOnRelayToggle— boolean; whether the controller chirps when the relay togglesautoUnlockSchedule— weekly schedule that latches the relay open during configured windows:{ enabled, windows: { monday: [{ from: "09:00", to: "17:00" }], ... } }in the facility's timezone. Cross-midnight windows are split automatically. Passnullto clear.
When device-side fields change, the tool also pushes the matching Balena env vars and an MQTT refresh so the controller picks up the new config immediately (best-effort; a Balena outage will not fail the save — note that an autoUnlockSchedule change triggers a container restart on the controller).
SAFETY: maintenanceMode force-open latches the door physically open, autoUnlockSchedule keeps it unlocked during its windows, and blockAllAccess removes every member authorization path. The AI assistant MUST confirm before applying these unless explicitly requested. Read the current door first.
Workflow: get the doorId (and current settings) from door_access_doors first.
Parameters
| Name | Type | Description |
|---|---|---|
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
doorId* | string | Door controller ID (balena UUID). Get it from door_access_doors (action list). |
blockAllAccess | boolean | Explicit member-access kill switch, evaluated before every allow path. |
geofenceOverride | objectnull | Per-door geofence override. null clears the override. |
icon | "door" | "door-sliding" | "door-double" | "garage" | "gate-barrier" | "pedestrian" | "security" | "office" | "delivery" | "locker" | Icon shown in the admin list and the mobile app. |
holdTimeSeconds | integer | Relay hold time on unlock, in seconds. |
maintenanceMode | "off" | "force-open" | "force-closed" | Maintenance override. force-open latches the relay open; force-closed blocks member unlocks. |
doorLocation | stringnull | Physical location label (max 64 chars). Empty string or null clears. |
playNotificationSoundOnRelayToggle | boolean | Whether the controller plays a chirp when the relay toggles. |
autoUnlockSchedule | objectnull | Weekly auto-unlock schedule { enabled, windows: { day: [{from,to}] } } (HH:MM, facility timezone). null clears. |
door_access_control_doorDoor & Gate AccessPhysically actions a Door & Gate Access (DGA) door controller: admin override unlock, or an identify beep to locate the device on-site.
This is the DGA module (Performance Hub managed door controllers), NOT the GymMaster partner integration — for partner-integration doors use facility_control_door instead.
Actions:
unlock— admin override unlock. Briefly toggles the relay using the door's configured hold time (the door auto-relocks). Writes anadmin-overrideaudit row. This is the explicit admin escape hatch and bypasses member authorization, including force-closed maintenance and blockAllAccess. Requires areason.identify— plays a short locator beep pattern (3 beeps, ~2 seconds) on the door controller so someone on-site can find it. Diagnostic only; no audit row.
SAFETY: unlocking a door is a physical security action. The AI assistant MUST confirm with the user before unlocking unless the user explicitly and unambiguously asked to unlock that specific door.
Workflow: if you don't know the doorId, call door_access_doors with action list first — do NOT guess door IDs.
Returns (unlock): commandId, the audit eventId, holdTimeSeconds used, and whether force-closed maintenance mode was bypassed. The command is dispatched fire-and-forget; device confirmation is not awaited.
Parameters
| Name | Type | Description |
|---|---|---|
action* | "unlock" | "identify" | `unlock` = admin override unlock (auto-relocks); `identify` = locator beep. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
doorId* | string | Door controller ID (balena UUID). Get it from door_access_doors (action list). |
reason | string | Reason for the unlock, stored in the audit log. REQUIRED for unlock. If the user did not state one, generate a professional reason from the conversation context. |
door_access_doorsDoor & Gate AccessRead-only tool for the Door & Gate Access (DGA) module: lists the door controllers at a facility and fetches a single door's live device status.
This is the DGA module (mobile-app door unlocking managed in Performance Hub), NOT the GymMaster partner integration — for partner-integration doors use facility_control_door instead.
Actions:
list— every door controller with live status, maintenanceMode, explicitblockAllAccess, Access ScopegroupIds, whether it has rule/geofence/time-window overrides, fully merged effective rules,effectiveTimeWindowAccess, facility timezone, and device settings.device_status— Balena + heartbeat snapshot for one door (requires doorId): update status, IP address, network source, WiFi SSID, hardware make/model/serial, OS/supervisor/application versions, uptime, CPU usage/temperature, memory usage. Returnsdata: nullwhen no telemetry is available.
Use this tool when:
- The user asks which doors exist at a facility, whether a door is online, or what rules/geofence apply to a door
- You need a doorId before calling door_access_control_door or door_access_configure_door
- Troubleshooting an offline or misbehaving door controller (device_status)
Note: adding/decommissioning door controllers is done via Device Management, not this module.
Parameters
| Name | Type | Description |
|---|---|---|
action* | "list" | "device_status" | `list` = all doors at the facility; `device_status` = telemetry snapshot for one door. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
doorId | string | Door controller ID (balena UUID). Required for device_status. Get it from the list action. |
door_access_eventsDoor & Gate AccessRead-only tool for the Door & Gate Access (DGA) module's Access Logs — the audit trail of every unlock attempt at a facility.
Returns door-access events newest-first by default. Set view to no_visit_recorded to return elapsed user-specific one-time windows with no successful unlock. That opt-in view is separate from actual door activity and excludes weekly windows and policy schedules.
Each event includes the doorId, who attempted it (personID — a User Access userId for members, or the admin's email for admin overrides), the state/outcome, timestamps, and request metadata (source, geolocation result, user agent).
Parameters:
from/to— unix-seconds time window (optional)limit— max events to return (default 100, capped at 500)- The response includes
lastEvaluatedKeywhen more pages exist; narrow the time window to page through history.
Use this tool when:
- The user asks who unlocked a door, when, or why an unlock was denied
- Auditing admin override unlocks
- Investigating door activity over a time period
Parameters
| Name | Type | Description |
|---|---|---|
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
view | "door_events" | "no_visit_recorded" | Door events by default, or elapsed one-time windows with no successful visit. |
from | integer | Window start (unix seconds). Optional. |
to | integer | Window end (unix seconds). Optional. |
limit | integer | Maximum events to return (default 100, max 500). |
cursor | string | Pagination cursor returned by the no-visit view. |
door_access_invitationsDoor & Gate AccessBulk Door & Gate Access mobile-app invitations: emails users a link to install and sign in to the app. Two-step preview -> send flow.
(For a single user, use door_access_manage_users with action resend_invite instead.)
Actions:
preview— computes the candidate recipients WITHOUT sending anything. Base pool: every non-deleted user with an email who has never used the app. By default it is narrowed to users who currently have access and have never been invited; widen with:includeAlreadyInvited: true— also re-send to previously-invited usersincludeNoAccess: true— also include users without any potential regular, permanent-grant, or enforce-mode time-window access. A valid future window counts as potential access.
Returns counts, a sample, and the full candidateuserIdslist for the send step.
send— emails the invitation to the supplieduserIds(max 50 per call; batch a longer preview list across multiple calls). Each user is re-validated at send time — rows that vanished, lost their email, or logged in since the preview are skipped, not failed. Returns per-user outcomes (sent / failed / skipped) and a summary.
SAFETY: send emails real users. ALWAYS run preview first, show the user the recipient count, and get their confirmation before calling send.
Parameters
| Name | Type | Description |
|---|---|---|
action* | "preview" | "send" | `preview` = dry-run candidate computation; `send` = email the invitations. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
includeAlreadyInvited | boolean | preview: also include users who already received an invitation (re-send). |
includeNoAccess | boolean | preview: also include users who do not currently have effective access. |
userIds | array | send: the recipients (from the preview), max 50 per call. |
door_access_manage_usersDoor & Gate AccessWrite tool for the Door & Gate Access (DGA) module's User Access list — creates, edits, and removes the people who can use the Door & Gate Access mobile app at a facility, and manages their grants, sync coupling, sessions, and invitations.
Use door_access_users (read tool) first to find userIds and inspect current state.
Actions:
create— manually add a person (userobject; at least one of mobilePhone/email required; phone is normalised to E.164).sendInvite: truealso emails the app invitation. Returns 409 with the existing user when phone/email already exists at the facility.bulk_create— import up to 200 people in one call (usersarray, same fields as create plus optionalaccessEnabledand permanentgrants). Time-window grants are intentionally not accepted in bulk; add them with set_time_window_grants. Per-row outcomes are reported individually.update— partial edit of any user fields (userId+userobject). Pass null to clear an optional field. IncludesaccessEnabled,autoMessageSuppressed, per-userappMessage, and optionaltimeWindowGrants.delete— soft-delete a user (userId). Access logs are preserved. Confirm with the user before deleting.set_grants— REPLACE the user's permanent grants (userId+grants: { facilityWide, doors[], groups[], accessHours? }).set_time_window_grants— REPLACE only admin-owned additive time-window grants (userId+timeWindowGrants[]). Existing permanent grants and partner-owned windows remain untouched. Empty [] explicitly clears admin windows.decouple— freeze the row against partner/CCTV sync updates and clear all partner-owned source windows (admin takes manual control).recouple— re-attach the row to sync updates.logout— revoke all of the user's mobile-app sessions (refresh tokens, matched by their phone/email).resend_invite— force-send the app invitation email (requires the user to have an email on file).
Before replacing grants: use door_access_users get and effective_access first, present the doors and time bounds gained/lost, and obtain confirmation unless the user explicitly requested that exact replacement.
User object fields (create / update): firstName, lastName, mobilePhone, email, type, membershipStatus, tags[], customTags[], notes, accessEnabled, autoMessageSuppressed, appMessage, timeWindowGrants[].
Parameters
| Name | Type | Description |
|---|---|---|
action* | "create" | "bulk_create" | "update" | "delete" | "set_grants" | "set_time_window_grants" | "decouple" | "recouple" | "logout" | "resend_invite" | The operation to perform. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
userId | string | User Access row ID. Required for update, delete, set_grants, set_time_window_grants, decouple, recouple, logout, resend_invite. |
user | object | User fields for create / update (including optional additive timeWindowGrants). |
users | array | bulk_create rows (max 200). Same fields as user, plus optional grants { facilityWide, doors[], groups[] }. |
sendInvite | boolean | create / bulk_create: also send the app invitation email to users with an email address. |
grants | object | set_grants: REPLACES the grants — { facilityWide: boolean, doors: string[], groups: string[], accessHours?: object }. |
timeWindowGrants | array | set_time_window_grants: REPLACES admin-owned scoped time windows. [] explicitly clears them. |
door_access_scopesDoor & Gate AccessManages Door & Gate Access "Access Scopes" (door groups) at a facility — named sets of doors that Access Policies can target, that can carry geofence overrides, and that users can be granted via door_access_manage_users.
A door can belong to multiple scopes. Access Policy exclusions take precedence over policy targets.
Actions:
list— all scopes at the facility (name, description, doorIds, and geofence override state)get— one scope by groupIdcreate— new scope.namerequired; optional description, doorIds[], geofenceOverrideupdate— partial edit (groupId + any of the same fields). doorIds REPLACES the door list when supplied.delete— soft-delete a scope (groupId). Users granted access via this scope lose that grant path. Confirm with the user before deleting.
For updates that replace doorIds, read the scope and affected policies first, show the access impact, and confirm unless the user explicitly requested the exact change.
Parameters
| Name | Type | Description |
|---|---|---|
action* | "list" | "get" | "create" | "update" | "delete" | The operation to perform. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
groupId | string | Scope (door group) ID. Required for get, update, delete. |
name | string | Scope name (required for create, max 120 chars). |
description | stringnull | Optional description (max 2000 chars). null/empty clears. |
doorIds | arraynull | Door controller IDs in this scope. REPLACES the list when supplied; null empties it. |
geofenceOverride | objectnull | Scope-level geofence override. null clears. |
door_access_settingsDoor & Gate AccessReads and writes the facility-level Door & Gate Access settings (the module's Settings tab), and dry-runs geofence evaluations.
Actions:
get_policies/update_policies— read or atomically replace the versioned Access Policies document. A policy combines audience (who), targets (where), and an anytime or scheduled window set (when). Always preserve and submit the current revision.create_policy/update_policy/duplicate_policy/delete_policy— make one revision-checked policy change without replacing unrelated policies.policy_impact— count current users and doors affected by one policy before editing or deleting it.get_rules— reads the shared facility settings document used for non-policy controls:geofence— { enabled, center {lat,lng}, centerOverridden, radiusMeters, accuracyBufferMeters, requireAccuracyBetterThan }accessTimeWindowGrace— facility-wide early/late access minutes applied to every policy, user, and integration windowappLock— facility-enforced mobile-app re-authentication { enforced, graceSeconds (0-3600), allowedMethods [biometric|pin] }supportContacts— { mode: default|on|off } controls whether the app shows the club's support email/phoneappMessage— facility-wide app announcement { enabled, title, text, severity info|warning|critical, link {url,label}, startsAt, endsAt (unix seconds) }
update_rules— saves those non-policy settings. Always call get_rules first and return the complete document; authorization fields are preserved server-side and access must be changed with Access Policies.test_geofence— dry-run a geofence evaluation for a coordinate (lat,lng, optionalaccuracyMetersanddoorIdto include that door's override). Returns the effective geofence and the pass/fail result — nothing is modified.
Sync settings live in door_access_sync; automated per-user messages in door_access_auto_messages.
Parameters
| Name | Type | Description |
|---|---|---|
action* | "get_rules" | "update_rules" | "get_policies" | "update_policies" | "create_policy" | "update_policy" | "duplicate_policy" | "delete_policy" | "policy_impact" | "test_geofence" | The operation to perform. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
rules | object | update_rules: the full settings document. Authorization is managed through Access Policies and preserved server-side. |
accessPolicyConfig | object | update_policies: complete Access Policy configuration returned by get_policies. |
policy | object | create_policy/update_policy: complete Access Policy object. |
revision | integer | Policy CRUD: current Access Policy revision returned by get_policies. |
policyId | string | policy_impact: stable policy ID. |
lat | number | test_geofence: latitude of the test pin. |
lng | number | test_geofence: longitude of the test pin. |
accuracyMeters | number | test_geofence: reported GPS accuracy in metres (optional). |
doorId | string | test_geofence: evaluate against this door's geofence override instead of just the facility default (optional). |
door_access_syncDoor & Gate AccessManages Door & Gate Access User Access syncing — pulling people in from the facility's partner integrations (member-management systems) and CCTV — plus the partner-synced bulk-delete flow and the sync troubleshooting log.
Actions:
partners— partner integrations, synced user counts, and each partner's source time-window mappingget_config— sync config, including per-partnertimeWindowAccess: { mappings, freshness }and nestedappInvitationseligibility/rulesupdate_config— update admin-controlled sync config while preserving omitted fields. Source mappings translate partnerscopeKeyvalues to facilityWide/doors/groups. Enabled advanced invitation rules replace the simple recipient mode and choose synced recipients by membershipStatus/type/tag/source/partnerId without requiring current door access; automatic invitations always require email, exclude disabled/conflicted users, send once, and never grant access.run— run an on-demand sync now (also runs nightly). Synchronously sweeps every enabled source and returns per-source counts (processed / created / updated / skipped)log— recent sync outcomes newest-first with the reason a member did or didn't sync (limitdefault 100, max 500)bulk_delete_preview— dry-run of deleting partner-synced users (optionally scoped to onepartnerId). Returns the affected count, a sample, and aconfirmToken. Nothing is modified.bulk_delete— execute the soft-delete. Requires theconfirmTokenfrom the preview; if the user set changed since the preview the call is rejected (409) and you must re-preview. Access logs are preserved, but admin customisations on the deleted rows (grants, custom tags, notes) are lost.
SAFETY: bulk_delete removes potentially thousands of users' app access. ALWAYS run bulk_delete_preview first, show the user the count, and get their explicit confirmation before calling bulk_delete. For update_config, call get_config first, preserve unrelated partner/source/invitation settings, show mapping/freshness/invitation changes, and confirm material authorization changes.
Parameters
| Name | Type | Description |
|---|---|---|
action* | "partners" | "get_config" | "update_config" | "run" | "log" | "bulk_delete_preview" | "bulk_delete" | The operation to perform. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
config | object | update_config: partial sync config patch. Omitted settings are preserved. Read get_config first. |
partnerId | string | bulk_delete_preview / bulk_delete: limit to one partner. Omit to target all partner-synced users. |
confirmToken | string | bulk_delete: the token returned by bulk_delete_preview. REQUIRED. |
limit | integer | log: max entries to return (default 100, max 500). |
door_access_usersDoor & Gate AccessRead-only tool for the Door & Gate Access (DGA) module's User Access list — the people who can sign in to the Door & Gate Access mobile app at a facility.
Actions:
list— all non-deleted User Access rows, each with computedhasAccess(could pass an Access Policy, permanent grant, or time window now or in the future) and source-window freshness. Supports filters:search— free text across name, phone, email, tagssource— all | manual | partner | cctv (where the row came from)accessEnabled— any | true | false (the per-user kill switch)hasGrants— any | true | false (has personal grants)hasAccess— any | true | false (computed effective access)
get— one User Access row by userId, including admintimeWindowGrants, integrationsourceTimeWindows, and freshness.effective_access— current per-door decision plus configured authorization paths:allowedNow, deterministicallowedVia/deniedReason, block/maintenance state, active/next time-window availability, scopes, and source freshness. Use this before any grant replacement.people_config— the distinct person types, membership statuses, and tags present at the facility (useful for building Access Policy audiences that match real data).
Use this tool when:
- The user asks who can unlock doors, whether a specific person has access, or why someone does/doesn't have access
- You need a userId before calling door_access_manage_users
- Building or reviewing Access Policies and you need the real type/status/tag values (people_config)
Parameters
| Name | Type | Description |
|---|---|---|
action* | "list" | "get" | "effective_access" | "people_config" | `list` = filtered user list; `get` = single user; `effective_access` = per-door current/future attribution; `people_config` = distinct types/statuses/tags. |
facilityId | string | Facility ID. Falls back to the currently selected facility when omitted. |
userId | string | User Access row ID. Required for get and effective_access. |
search | string | list filter: free-text search across name, phone, email, and tags. |
source | "all" | "manual" | "partner" | "cctv" | list filter: where the row came from. Default all. |
accessEnabled | "any" | "true" | "false" | list filter: per-user access kill switch state. Default any. |
hasGrants | "any" | "true" | "false" | list filter: whether the user has personal grants. Default any. |
hasAccess | "any" | "true" | "false" | list filter: computed effective access (policy match or grant). Default any. |
hideExcluded | boolean | list filter (legacy): hide synced users with no effective access; the response then includes a hidden { count, sample } envelope. Prefer the hasAccess filter. |