Skip to content
OpenAppPhysical access, fully managed
Login

Build an agent that controls physical access

An access-control agent (or integration bot) calls OpenApp on behalf of an operator: list doors, open a gate when a parcel arrives, or revoke a guest invite at checkout. This guide covers the minimum wiring — credentials, org scope, and executing switchable.open safely.

For sector-specific workflows (private home, STR, hotel, campus, locker), pair this with Integrate OpenApp with your existing software and Model by sector.

  1. An OpenApp account with permission to manage the target organization.
  2. An API key for server-to-server use.
  3. The organization id (ULID) and at least one entity id for a door or gate (from the dashboard or GET /entities).

Store secrets in environment variables — never embed keys in prompts, llms.txt, or public repos.

Terminal window
export OPENAPP_API_BASE='https://openapp.house/api/v1'
export OPENAPP_API_KEY='https://openapp.house_openapp_YOUR_SECRET'
export OPENAPP_ORG_ID='01HORG00000000000000000000'
export ENTITY_ID='01HENTITY000000000000000000'

Many routes are scoped to an organization. Pass the org id in the X-Org header when the API reference or Organization context docs say it is required (for example GET /devices, integration admin routes).

SDK

devices = await client.devices.list()

Pass org context via client headers where required — see Organization context.

HTTP API (curl)

Terminal window
curl -sS "${OPENAPP_API_BASE}/devices" \
-H "X-API-Key: ${OPENAPP_API_KEY}" \
-H "X-Org: ${OPENAPP_ORG_ID}"

Doors and relays use entity actions. The common unlock action is switchable.open — the same call as Open the door with the HTTP API.

SDK

await client.entities.actions(entity_id, "switchable.open")

Pass org context on list calls via headers where required — see Entities and Organization context.

HTTP API (curl)

Terminal window
curl -sS -X POST \
-H "X-API-Key: ${OPENAPP_API_KEY}" \
-H "Content-Type: application/json" \
-H "X-Org: ${OPENAPP_ORG_ID}" \
-d '{}' \
"${OPENAPP_API_BASE}/entities/${ENTITY_ID}/actions/switchable.open"

Agents should list or resolve entities instead of hard-coding ids when possible:

  1. GET /integrations → pick the Virtual Access or hardware integration.
  2. GET /integrations/{id}/entities or GET /entities with pagination.
  3. Match entity_type and metadata (door name, zone, external id).
  4. Call POST /entities/{id}/actions/{action_id} only on the resolved id.

See Agent-relevant API index for operation groupings.

RiskMitigation
Wrong door openedResolve entity by id + human-readable label; confirm in UI for first deploy.
Stale or stolen API keyRotate keys in the dashboard; use dedicated scoped keys or agent credentials. A scoped credential reaches only the routes and roles in its scope and gets 403 everywhere else.
Agent reaches the wrong doorsSet the agent’s allowed_entity_ids; it is intersected with the key’s entity list. An agent with no list is not entity-restricted.
Unattended unlockSet the agent’s confirmation mode (always or physical_only) so opens need a preview token; document org policy.
Door not classifiedswitchable.open and switchable.toggle return 409 (life_safety_class_required or life_safety_attestation_required) until the opening is classified and attested — see Life safety and egress.
Audit trailEvery switchable.* action is recorded as entity.action.succeeded or entity.action.denied, attributed to the agent, API key, or user. Pull it with the audit API, export it, or stream it to your endpoint with HMAC-signed webhooks — see Query access and audit activity.

OpenApp orchestrates access; life-safety and compliance remain the operator’s responsibility — see Access control architecture.