Skip to content
OpenAppPhysical access, fully managed
Login

Provision a building with OpenApp Scripting

Multi-site rollouts (campus wings, new apartment towers, demo environments) repeat the same steps: integrations, devices, entities, portals. OpenApp Scripting runs Rhai programs server-side as asynchronous executions — submit with POST /scripting/executions, then poll the job for the result — ideal for one-shot provisioning jobs and CI pipelines.

This guide is for platform engineers automating building setup. Syntax reference: OpenApp Scripting. Getting started: Scripting step.

  • An unscoped API key with scripting execute permission in at least one org. Scoped credentials (voice keys, keys with scoped_roles, agent credentials) can’t run scripting.
  • A tested script in the interactive shell or a .openapp file

Scripting does not take X-Org on the wire. Each operation names its own org (for example org_id on create), and OpenApp checks the same permission the matching HTTP route checks, in that resource’s org. Creates also count against plan quotas and are refused for a degraded org, the same as over HTTP.

SDK

import asyncio
from pathlib import Path
job = await client.scripting.create_execution(
script='entity_action("01HENTITY...", "switchable.open", #{})'
)
# Poll until terminal — bounded at 16 minutes (runtime cap is 15).
TERMINAL = {"succeeded", "failed", "canceled"}
deadline = asyncio.get_event_loop().time() + 960
while job.get("status") not in TERMINAL:
if asyncio.get_event_loop().time() >= deadline:
raise TimeoutError(f"execution {job['id']} did not finish")
await asyncio.sleep(2.0)
job = await client.scripting.get_execution(job["id"])
print(job["status"], job["result"])
# Or read a .openapp file and submit its contents:
result = await client.scripting.execute(
script=Path("provision-wing-a.openapp").read_text()
)

Replace the script body with your provisioning program (create integration, devices, entities — see reference for built-ins). Every SDK returns the job first; keep polling until status is terminal.

HTTP API (curl)

Terminal window
export OPENAPP_API_BASE='https://openapp.house/api/v1'
export OPENAPP_API_KEY='https://openapp.house_openapp_YOUR_SECRET'
# 1. Submit — 202 Accepted with the execution job.
EXECUTION_ID=$(curl -sS -X POST \
-H "X-API-Key: ${OPENAPP_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"script": "print(\"provision batch start\");"
}' \
"${OPENAPP_API_BASE}/scripting/executions" | jq -r '.id')
# 2. Poll until terminal — bounded at 200 x 5s (runtime cap is 15 minutes).
attempt=0
while [ "$attempt" -lt 200 ]; do
JOB=$(curl -sS -H "X-API-Key: ${OPENAPP_API_KEY}" \
"${OPENAPP_API_BASE}/scripting/executions/${EXECUTION_ID}")
case "$(printf '%s' "$JOB" | jq -r '.status')" in
succeeded|failed|canceled) break ;;
esac
attempt=$((attempt + 1))
sleep 5
done
# 3. Read the outcome.
printf '%s' "$JOB" | jq '{ status, result, error }'
// Adapt to your org and provider types (see the scripting reference).
let org_id = "01HORG00000000000000000000";
let site = create("integration", #{
org_id: org_id,
provider_type: "virtual_access",
name: #{ en: "Tower A" },
});
// create devices, entities, portals under site.id ...

create("integration", …) needs org_id and provider_type; name is a localized map. See Resource kinds and fields.

Keep scripts idempotent where possible (check before create) and run against a staging org first.

Use scriptingUse SDK / HTTP directly
Many chained steps in one jobSingle invite or door action
CI template copied per buildingPMS webhook on each check-in
Operator-maintained .openapp filesProduction microservice

← Release locker compartment · go2rtc door camera →