Delegate apartment resident management via API
Shared apartment buildings need delegation: the building operator owns the intercom and common doors, while each apartment manages its own residents for directory display and permissions. OpenApp exposes this through building users on a Virtual Access integration (/integrations/{id}/building-users).
This guide is for integrators and building admins automating resident lists — not for guests. See Model by sector (shared apartment building).
Prerequisites
Section titled “Prerequisites”- Virtual Access integration id (
INTEGRATION_ID) - Organization id and API key with permission to update the integration
- Target user’s OpenApp
user_idand the role string your deployment expects (often scoped to the integration)
Full SDK reference: Apartment residents.
List current building users
Section titled “List current building users”SDK
rows = await client.apartment_residents.list(integration_id)const rows = await fetch( `${apiBase}/integrations/${integrationId}/building-users`, { headers: { authorization: `Bearer ${apiKey}`, "x-org": orgId, }, },).then((r) => r.json());use openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;
let path = format!("/integrations/{integration_id}/building-users");let rows: Vec<serde_json::Value> = client .transport() .request_json(RequestSpec { method: Method::GET, path: &path, extra_headers: &[("X-Org", org_id)], ..Default::default() }) .await?;resp, err := client.ApartmentResidentsAPI.ListBuildingUsers(ctx, integrationID). XOrg(orgID). Execute()if err != nil { return err}defer resp.Body.Close()Ensure X-Org is sent if your client does not inject it automatically — see the Apartment residents note on headers.
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 INTEGRATION_ID='01HINTEGRATION00000000000000'
curl -sS \ -H "Authorization: Bearer ${OPENAPP_API_KEY}" \ -H "X-Org: ${OPENAPP_ORG_ID}" \ "${OPENAPP_API_BASE}/integrations/${INTEGRATION_ID}/building-users"Add a resident to an apartment’s delegation
Section titled “Add a resident to an apartment’s delegation”SDK
await client.apartment_residents.add( integration_id, user_id=user_id, role=role_string,)await fetch(`${apiBase}/integrations/${integrationId}/building-users`, { method: "POST", headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json", "x-org": orgId, }, body: JSON.stringify({ user_id: userId, role: roleString }),});use openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;use serde_json::json;
let path = format!("/integrations/{integration_id}/building-users");client .transport() .request_json::<serde_json::Value, _>(RequestSpec { method: Method::POST, path: &path, body: Some(&json!({ "user_id": user_id, "role": role_string })), extra_headers: &[("X-Org", org_id)], ..Default::default() }) .await?;payload := *openapiclient.NewAddBuildingUserPayload(roleString, userID)resp, err := client.ApartmentResidentsAPI.AddBuildingUser(ctx, integrationID). XOrg(orgID). AddBuildingUserPayload(payload). Execute()if err != nil { return err}defer resp.Body.Close()Replace role with the value shown in your org’s role catalog (API reference → Roles).
HTTP API (curl)
curl -sS -X POST \ -H "Authorization: Bearer ${OPENAPP_API_KEY}" \ -H "Content-Type: application/json" \ -H "X-Org: ${OPENAPP_ORG_ID}" \ -d '{ "user_id": "01HUSER00000000000000000000", "role": "virtual_access:integration:'"${INTEGRATION_ID}"':resident" }' \ "${OPENAPP_API_BASE}/integrations/${INTEGRATION_ID}/building-users"Remove a resident
Section titled “Remove a resident”SDK
await client.apartment_residents.remove(integration_id, user_id)await fetch( `${apiBase}/integrations/${integrationId}/building-users/${userId}`, { method: "DELETE", headers: { authorization: `Bearer ${apiKey}`, "x-org": orgId, }, },);use openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;
let path = format!("/integrations/{integration_id}/building-users/{user_id}");client .transport() .request_json::<(), ()>(RequestSpec { method: Method::DELETE, path: &path, extra_headers: &[("X-Org", org_id)], ..Default::default() }) .await?;resp, err := client.ApartmentResidentsAPI.DeleteBuildingUser(ctx, integrationID, userID). XOrg(orgID). Execute()if err != nil { return err}defer resp.Body.Close()HTTP API (curl)
curl -sS -X DELETE \ -H "Authorization: Bearer ${OPENAPP_API_KEY}" \ -H "X-Org: ${OPENAPP_ORG_ID}" \ "${OPENAPP_API_BASE}/integrations/${INTEGRATION_ID}/building-users/${USER_ID}"Automation patterns
Section titled “Automation patterns”| Pattern | Approach |
|---|---|
| Apartment portal in your app | On “add roommate”, call POST .../building-users |
| Sync from property DB | Nightly job: diff list vs source of truth |
| Offboarding | DELETE .../building-users/{user_id} on lease end |
Pair with Virtual intercom flow so delegated residents appear in the lobby directory.