Zones
Zones partition devices within an integration (floors, wings, apartments, …). 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.
There is no org-wide GET /zones in the public bundle: discovery is GET /integrations/{integration_id}/zones (list_integration_zones). POST /zones supplies integration_id in the body.
Operations vs wire routes
Section titled “Operations vs wire routes”| Concern | HTTP | operationId | Notes |
|---|---|---|---|
| List for integration | GET /integrations/{integration_id}/zones | list_integration_zones | X-Org required; optional include_deleted, only_deleted, include_metadata. Returns ZoneResponse[]. |
| Create | POST /zones | create_zone | Body CreateZoneRequest: integration_id, name (LocalizedString), optional parent_zone_id, external_id. |
| Get | GET /zones/{id} | get_zone | X-Org + optional deleted/metadata flags. |
| Update | PUT /zones/{id} | update_zone | Body UpdateZoneRequest. |
| Soft delete | DELETE /zones/{id} | delete_zone | |
| Hard delete | DELETE /zones/{id}/purge | hard_delete_zone |
SDK coverage
Section titled “SDK coverage”| Capability | Python | Rust (openapp_sdk) | Go | TypeScript (AsyncClient) |
|---|---|---|---|---|
| Lifecycle + list-by-integration | client.zones — create, get, update, delete, purge, by_integration | client.zones() — same | ZonesAPI | Not on façade |
Thin wrappers send JSON bodies matching OpenAPI; extend transport + RequestSpec when you need full query/header parity on every route variant.
Typical errors
Section titled “Typical errors”401 / 403 when the caller cannot access the org or integration.404 for unknown zone or integration ids.422 on invalid payloads.400 on list_integration_zones. Errors follow ApiErrorResponse — see Errors & retries.
Examples
Section titled “Examples”List zones for an integration
Section titled “List zones for an integration”zones = await client.zones.by_integration("int_abc123")Ensure org context ( X-Org ) is configured on the client for integration-scoped routes.
zones, httpResp, err := client.ZonesAPI.ListIntegrationZones(ctx, "int_abc123"). XOrg("org_123"). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = zonesuse openapp_sdk::Client;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let zones = client.zones().by_integration("int_abc123").await?;Add X-Org via transport extra_headers or interceptors when required by your deployment.
const url = new URL( `https://api.openapp.house/api/v1/integrations/${integrationId}/zones`,);url.searchParams.set("include_deleted", "false");url.searchParams.set("include_metadata", "false");
const zones = await fetch(url, { headers: { authorization: "Bearer v1_openapp_YOUR_SECRET", "x-org": orgId, },}).then((r) => r.json() as Promise<Array<{ id: string }>>);There is no org-wide GET /zones — discover zones through their integration. Replace with AsyncClient.listIntegrationZones once the Node façade exposes it.
Create a zone
Section titled “Create a zone”zone = await client.zones.create( integration_id="int_abc123", name={"value": {"en": "Lobby"}},)name := *openapiclient.NewLocalizedString(map[string]string{"en": "Lobby"})req := openapiclient.NewCreateZoneRequest("int_abc123", name)resp, httpResp, err := client.ZonesAPI.CreateZone(ctx). XOrg("org_123"). CreateZoneRequest(*req). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = respuse openapp_sdk::Client;use serde_json::json;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let zone = client .zones() .create(&json!({ "integration_id": "int_abc123", "name": { "value": { "en": "Lobby" } } })) .await?;const zone = await fetch("https://api.openapp.house/api/v1/zones", { method: "POST", headers: { authorization: "Bearer v1_openapp_YOUR_SECRET", "content-type": "application/json", "x-org": orgId, }, body: JSON.stringify({ integration_id: integrationId, name: { value: { en: "Lobby" } }, }),}).then((r) => r.json() as Promise<{ id: string; integration_id: string }>);Body matches CreateZoneRequest — name is wrapped in LocalizedString ({ value: { en: "…" } }), and parent_zone_id / external_id are optional. Replace with AsyncClient.createZone once the Node façade exposes it.
Get a zone (GET /zones/{id})
Section titled “Get a zone (GET /zones/{id})”X-Org is required; optional include_deleted / include_metadata query flags surface soft-deleted rows or expanded metadata 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.
zone, httpResp, err := client.ZonesAPI.GetZone(ctx, zoneID). XOrg(orgID). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = zoneAdd .IncludeDeleted(true) / .IncludeMetadata(true) when you need wire parity with the OpenAPI query.
use openapp_sdk::Client;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let zone = client.zones().get(zone_id).await?;Use transport() + RequestSpec with X-Org and query keys when the bare path is rejected by your gateway.
const url = new URL(`https://api.openapp.house/api/v1/zones/${zoneId}`);url.searchParams.set("include_deleted", "false");url.searchParams.set("include_metadata", "false");
const zone = await fetch(url, { headers: { authorization: "Bearer v1_openapp_YOUR_SECRET", "x-org": orgId, },}).then((r) => r.json());The optional include_deleted / include_metadata keys serialize as flat URLSearchParams entries (same shape as output_options in the rest of the SDK). Replace with AsyncClient.getZone once the Node façade exposes it.
Update a zone (PUT /zones/{id})
Section titled “Update a zone (PUT /zones/{id})”Body UpdateZoneRequest — all fields optional: name (LocalizedString), parent_zone_id, external_id. Replaces the row (no merge).
updated = await client.zones.update( zone_id, name={"value": {"en": "Lobby (renamed)"}},)import ( "context"
openapiclient "github.com/tomers/openapp-sdk/go")
name := openapiclient.NewLocalizedString(map[string]string{"en": "Lobby (renamed)"})upd := openapiclient.NewUpdateZoneRequest()upd.SetName(*name)updated, httpResp, err := client.ZonesAPI.UpdateZone(context.Background(), zoneID). XOrg(orgID). UpdateZoneRequest(*upd). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = updateduse openapp_sdk::Client;use serde_json::json;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let updated = client .zones() .update( zone_id, &json!({ "name": { "value": { "en": "Lobby (renamed)" } } }), ) .await?;const updated = await fetch(`https://api.openapp.house/api/v1/zones/${zoneId}`, { method: "PUT", headers: { authorization: "Bearer v1_openapp_YOUR_SECRET", "content-type": "application/json", "x-org": orgId, }, body: JSON.stringify({ name: { value: { en: "Lobby (renamed)" } }, }),}).then((r) => r.json());PUT replaces the row — fields you omit are dropped, not merged. Body matches UpdateZoneRequest with the same LocalizedString wrapper as create. Replace with AsyncClient.updateZone once the Node façade exposes it.
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. 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)_, httpResp, err := client.ZonesAPI.DeleteZone(ctx, zoneID). XOrg(orgID). Execute()if err != nil { return err}defer httpResp.Body.Close()
_, httpResp2, err := client.ZonesAPI.HardDeleteZone(ctx, zoneID). XOrg(orgID). Execute()if err != nil { return err}defer httpResp2.Body.Close()use openapp_sdk::Client;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
client.zones().delete(zone_id).await?;client.zones().purge(zone_id).await?;const headers = { authorization: "Bearer v1_openapp_YOUR_SECRET", "x-org": orgId,};
await fetch(`https://api.openapp.house/api/v1/zones/${zoneId}`, { method: "DELETE", headers,});
await fetch(`https://api.openapp.house/api/v1/zones/${zoneId}/purge`, { method: "DELETE", headers,});Soft delete leaves the row visible behind include_deleted=true; /purge is irreversible. There is no dedicated zone restore route — re-list with include_deleted=true before recreating. Replace with AsyncClient.deleteZone / hardDeleteZone once the Node façade exposes them.