Release a locker compartment via API
Parcel lockers and mailroom matrices release one compartment at a time when a recipient or courier is authorized. In OpenApp each compartment is modeled as a switchable entity — the same switchable.open action used for doors and gates.
This guide is for campus mail services, corporate mailrooms, and parcel-wall operators automating pickup. See Model by sector (locker / parcel matrix).
- One integration + devices represent the locker bank (or one device per compartment).
- Each compartment is an entity with a human-readable name in metadata.
- Your app validates a pickup code, then calls
switchable.openon that entity only.
Release one compartment
Section titled “Release one compartment”SDK
await client.entities.by_id(entity_id).open()const res = await fetch( `${apiBase}/entities/${entityId}/actions/switchable.open`, { method: "POST", headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json", "x-org": orgId, }, body: JSON.stringify({}), },);if (!res.ok) throw new Error(`open failed: ${res.status}`);use openapp_sdk::Client;use serde_json::json;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
client .entities() .invoke_action(entity_id, "open", &json!({})) .await?;httpResp, err := client.EntitiesAPI.ExecuteEntityAction(ctx, entityID, "open"). Body(map[string]interface{}{}). Execute()if err != nil { return err}defer httpResp.Body.Close()HTTP API (curl)
export OPENAPP_API_BASE='https://api.openapp.house/api/v1'export OPENAPP_API_KEY='v1_openapp_YOUR_SECRET'export OPENAPP_ORG_ID='01HORG00000000000000000000'export COMPARTMENT_ENTITY_ID='01HENTITY000000000000000000'
curl -sS -X POST \ -H "Authorization: Bearer ${OPENAPP_API_KEY}" \ -H "Content-Type: application/json" \ -H "X-Org: ${OPENAPP_ORG_ID}" \ -d '{}' \ "${OPENAPP_API_BASE}/entities/${COMPARTMENT_ENTITY_ID}/actions/switchable.open"Discover compartment entities
Section titled “Discover compartment entities”SDK
rows = await client.integrations.entities(integration_id)const url = new URL( `${apiBase}/integrations/${integrationId}/entities`,);url.searchParams.set("limit", "100");url.searchParams.set("offset", "0");url.searchParams.set("include_metadata", "false");
const page = await fetch(url, { headers: { authorization: `Bearer ${apiKey}`, "x-org": orgId, },}).then((r) => r.json());use openapp_sdk::Client;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let rows = client.integrations().entities(integration_id).await?;page, httpResp, err := client.IntegrationsAPI.ListIntegrationEntities(ctx, integrationID). XOrg(orgID). OutputOptions(*openapiclient.NewMultiResourceOutputOptionsQuery(false, false, false)). Pagination(openapiclient.PaginationQuery{ Limit: openapiclient.PtrInt32(100), Offset: openapiclient.PtrInt32(0), }). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = pageHTTP API (curl)
curl -sS \ -H "Authorization: Bearer ${OPENAPP_API_KEY}" \ -H "X-Org: ${OPENAPP_ORG_ID}" \ "${OPENAPP_API_BASE}/integrations/${INTEGRATION_ID}/entities?limit=100&offset=0"Map external ids (compartment numbers) to entity ids during provisioning — provision a building with scripting for bulk setup.
Safety
Section titled “Safety”- Never open by numeric guess — resolve entity id from your parcel system’s authoritative mapping.
- Rate-limit automated release endpoints exposed to couriers.
- Log compartment id + correlation id for support (audit activity).