Skip to content
OpenAppPhysical access, fully managed
Login

Zones

Zones are org-owned physical spaces (buildings, floors, rooms) that hold devices and entities from any integration. See the Zones reference for validation, delete, merge, and placement rules. All routes require X-Org — see Organization context & pagination. Response bodies follow ZoneResponse; mutations use CreateZoneRequest / UpdateZoneRequest (both use LocalizedString for display names) — see the API reference.

Zones are listed per org with GET /zones or GET /zones/tree. POST /zones takes the org from X-Org; there’s no integration_id in the body.

ConcernHTTPoperationIdNotes
List (org scope)GET /zoneslist_zonesX-Org required; optional parent_zone_id, root=true, q, limit, offset, include_deleted, only_deleted.
TreeGET /zones/treeget_zone_tree{ items: ZoneTreeNode[] } with direct device_count / entity_count.
CreatePOST /zonescreate_zoneBody CreateZoneRequest: name (LocalizedString), optional parent_zone_id. 422 for a missing, deleted, foreign-org, or cyclic parent.
GetGET /zones/{id}get_zoneIncludes provider_links.
SummaryGET /zones/{id}/summaryget_zone_summarypath, children, and counts for a room view.
UpdatePUT /zones/{id}update_zoneBody UpdateZoneRequest: optional name, parent_zone_id (null makes it a root).
MergePOST /zones/{id}/mergemerge_zonesBody { source_zone_ids }. Needs zones:update and zones:delete.
Soft deleteDELETE /zones/{id}delete_zone409 zone_in_use while referenced; ?cascade=detach clears references.
Hard deleteDELETE /zones/{id}/purgehard_delete_zone
CapabilityPythonRust (openapp_sdk)GoTypeScript (AsyncClient)
Lifecycle + org listingclient.zones — list, tree, get_by_name, create, get, update, delete, purgeclient.zones() — sameZonesAPINot on façade

Thin wrappers send JSON bodies matching OpenAPI; extend transport + RequestSpec when you need full query/header parity on every route variant.

401 / 403 when the caller can’t access the org. 404 for unknown zone ids. 422 for an invalid parent or a zone in another org. 409 zone_in_use on delete without cascade=detach. 400 for a malformed zone_id filter. Errors follow ApiErrorResponse — see Errors & retries.

zones = await client.zones.list("org_123")
tree = await client.zones.tree()
zone = await client.zones.create(
name={"value": {"en": "Lobby"}},
parent_zone_id=floor_id,
)

X-Org is required; optional include_deleted / only_deleted query flags surface soft-deleted rows for dashboards.

zone = await client.zones.get(zone_id)

For deleted/metadata flags, send the request via AsyncClient._request with explicit query keys until the helper exposes them.

Body UpdateZoneRequest — all fields optional: name (LocalizedString), parent_zone_id (null makes it a root zone). A new parent is validated like create. Replaces the row (no merge).

updated = await client.zones.update(
zone_id,
name={"value": {"en": "Lobby (renamed)"}},
)

Soft delete and hard delete (DELETE /zones/{id}, DELETE /zones/{id}/purge)

Section titled “Soft delete and hard delete (DELETE /zones/{id}, DELETE /zones/{id}/purge)”

delete_zone is reversible at the data layer (the row stays under include_deleted=true); hard_delete_zone removes the row irrecoverably. Both require X-Org. Soft delete returns 409 zone_in_use while child zones, devices, or explicit entities reference the zone; add cascade=detach to clear them first (see Deleting a zone). There is no dedicated restore route in the published bundle — recover by re-querying with include_deleted=true and re-creating if needed.

await client.zones.delete(zone_id)
await client.zones.purge(zone_id)