Skip to content
OpenAppPhysical access, fully managed
Login

Populate a site and open a gate from a script

Everything you can do in the dashboard to set up a site can be done from a script: create zones, add a device and its doors, invite people, organize them in groups, and open a gate. This page walks the whole path with curl. Every SDK exposes the same operations; see SDKs.

Operations that belong to the OpenApp apps rather than the API (for example the dashboard copilot and billing checkout) are not available to API keys. Everything below is in the API reference.

Create the key in Settings → API keys, or over HTTP with an administrator’s credentials. Grant only the roles the script needs. A setup script that creates zones and devices, invites people, and opens doors:

{
"name": "Site setup script",
"expires_in": "P7D",
"scoped_roles": [
"zones:create", "zones:read", "zones:list", "zones:update", "zones:delete",
"devices:create", "devices:read", "devices:list", "devices:update", "devices:delete",
"entities:create", "entities:read", "entities:list", "entities:set_state",
"integrations:read", "integrations:list",
"users:create", "users:list"
]
}

See API keys for every role a key can carry. Groups are managed with an unscoped key. Delete the key when the script is done.

Terminal window
export OPENAPP_API_BASE='https://openapp.house/api/v1'
export OPENAPP_API_KEY='https://openapp.house_openapp_YOUR_SECRET'
export ORG='YOUR_ORG_ID'
call() { curl -sS -H "X-API-Key: ${OPENAPP_API_KEY}" -H "X-Org: ${ORG}" -H 'Content-Type: application/json' "$@"; }

Zones model the physical layout. Create a root zone, then a child:

Terminal window
LOBBY=$(call -X POST "${OPENAPP_API_BASE}/zones" -d '{"name":{"en":"Lobby"}}' | jq -r .id)
call -X POST "${OPENAPP_API_BASE}/zones" \
-d "{\"name\":{\"en\":\"Garage\"},\"parent_zone_id\":\"${LOBBY}\"}"

A device belongs to an integration. List yours, then create the device in a zone and one entity per door:

Terminal window
INTEGRATION=$(call "${OPENAPP_API_BASE}/integrations" | jq -r '.items[0].id')
DEVICE=$(call -X POST "${OPENAPP_API_BASE}/devices" -d "{
\"org_id\": \"${ORG}\",
\"name\": {\"en\": \"Lobby opener\"},
\"integration_id\": \"${INTEGRATION}\",
\"zone_id\": \"${LOBBY}\"
}" | jq -r .id)
DOOR=$(call -X POST "${OPENAPP_API_BASE}/entities" -d "{
\"device_id\": \"${DEVICE}\",
\"entity_type\": \"door\",
\"name\": \"Front door\"
}" | jq -r .id)

Provider-specific fields (device_metadata, external_id) depend on the integration; read them from GET /integrations/provider-types/{provider_type}/definition. A door is classified for life safety before it can be opened; see Life safety and egress.

People join an organization by invitation, by email or phone. The invitation carries the roles the person receives on accepting:

Terminal window
call -X POST "${OPENAPP_API_BASE}/orgs/${ORG}/invitations" \
-d '{"email":"resident@example.com","default_roles":["member"]}'

Direct user creation, POST /users, is limited to platform administration. People you invite appear in GET /orgs/{id}/users once they accept.

Groups (households, teams, tenants) are created in an organization and hold people. An unscoped key, or an agent whose organization enables agent_group_write, manages them:

Terminal window
GROUP=$(call -X POST "${OPENAPP_API_BASE}/orgs/${ORG}/groups" \
-d '{"name":{"en":"Floor 3"},"kind":"team"}' | jq -r .id)
call -X POST "${OPENAPP_API_BASE}/groups/${GROUP}/members" \
-d "{\"user_id\":\"${USER_ID}\",\"role\":\"member\"}"

Preview the action, then run it. Opening needs entities:set_state:

Terminal window
call -X POST "${OPENAPP_API_BASE}/entities/${DOOR}/actions/switchable.open/preview" -d '{}'
call -X POST "${OPENAPP_API_BASE}/entities/${DOOR}/actions/switchable.open" -d '{}'

For a key that does nothing but open one door, mint a voice key or give the key entities:set_state and a single entity in scoped_entity_ids.

Soft-delete what the script created, and restore it if you made a mistake:

Terminal window
call -X DELETE "${OPENAPP_API_BASE}/entities/${DOOR}"
call -X POST "${OPENAPP_API_BASE}/entities/${DOOR}/restore"
call -X DELETE "${OPENAPP_API_BASE}/zones/${LOBBY}?cascade=detach"

For larger rollouts, run the whole setup as one server-side program with OpenApp Scripting.