Apartment Residents
Apartment Residents routes manage building users for a virtual access integration: principals that hold an org role like virtual_access:integration:{id}:*. All three operations require X-Org and bearer_auth; path id is the integration ULID (see Integrations and Organization context & pagination).
OpenAPI groups these under /integrations/{id}/building-users (and .../{user_id} for removal). AddBuildingUserPayload requires user_id and role strings — paste the role your deployment expects (often scoped to that integration); see schemas in the API reference.
Operations vs wire routes
Section titled “Operations vs wire routes”| Concern | HTTP | operationId | Notes |
|---|---|---|---|
| List users | GET .../building-users | list_building_users | Path id = integration.200 body is an array per bundle (no named response schema in the public YAML). |
| Add user | POST .../building-users | add_building_user | AddBuildingUserPayload. 201 created. |
| Remove user | DELETE .../building-users/{user_id} | delete_building_user | 204 empty body on success. |
SDK coverage
Section titled “SDK coverage”| Capability | Python | Rust (openapp_sdk) | Go | TypeScript (AsyncClient) |
|---|---|---|---|---|
| List | client.apartment_residents.list(id) → list[dict] | Thin apartment_residents().list omits X-Org — use transport() + RequestSpec (see examples) when the gateway requires the header | ApartmentResidentsAPI.ListBuildingUsers + .XOrg(...) | Not on façade yet |
| Add | apartment_residents.add(id, user_id=…, role=…) | Same: prefer transport() + RequestSpec below for strict header parity | AddBuildingUser + payload + .XOrg(...) | Not on façade yet |
| Remove | apartment_residents.remove(id, user_id) | Same | DeleteBuildingUser + .XOrg(...) | Not on façade yet |
The Go generator returns raw *http.Response for these operations (no typed decode in the client) — decode JSON yourself from Body on success.
Typical errors
Section titled “Typical errors”401 / 403 for auth and org policy; 404 when the integration (or user, for delete) is missing; 400 for invalid payloads. Error bodies where returned follow ApiErrorResponse — see Errors & retries.
Examples
Section titled “Examples”Constants below stand in for real ULIDs from your org.
rows = await client.apartment_residents.list(integration_id)OpenAPI requires X-Org on list_building_users. If your bridge does not inject it from the default org, use interceptors or mirror the transport + RequestSpec pattern from the Rust tab with your HTTP client.
X-Org is mandatory on the request builder.
import ( "context" "encoding/json" "io")
resp, err := client.ApartmentResidentsAPI.ListBuildingUsers(context.Background(), integrationId). XOrg(orgId). Execute()if err != nil { return err}defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)if err != nil { return err}var rows []map[string]anyif err := json.Unmarshal(b, &rows); err != nil { return err}_ = rowsX-Org is required on the wire. The high-level apartment_residents() helpers do not attach it — use transport() (same idea as Org context & pagination):
use openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let org_id = "01HORG00000000000000000000".to_string();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?;const rows = await fetch( `https://api.openapp.house/api/v1/integrations/${integrationId}/building-users`, { headers: { authorization: "Bearer v1_openapp_YOUR_SECRET", "x-org": orgId, }, },).then( (r) => r.json() as Promise<Array<{ user_id: string; role: string }>>,);The path id is the integration ULID, not the apartment / building. X-Org is required by the wire even though the integration id already implies an org. Replace with AsyncClient.listBuildingUsers once the Node façade exposes it.
Add and remove a building user
Section titled “Add and remove a building user”created = await client.apartment_residents.add( integration_id, user_id=user_ulid, role=role_string,)await client.apartment_residents.remove(integration_id, user_ulid)Same X-Org requirement as for GET — ensure the wire request carries the header for POST / DELETE.
import ( "context"
openapiclient "github.com/tomers/openapp-sdk/go")
payload := *openapiclient.NewAddBuildingUserPayload(roleString, userUlid)resp, err := client.ApartmentResidentsAPI.AddBuildingUser(context.Background(), integrationId). XOrg(orgId). AddBuildingUserPayload(payload). Execute()if err != nil { return err}defer resp.Body.Close()
delResp, err := client.ApartmentResidentsAPI.DeleteBuildingUser( context.Background(), integrationId, userUlid,).XOrg(orgId).Execute()if err != nil { return err}defer delResp.Body.Close()use openapp_sdk::{Client, transport::RequestSpec};use reqwest::Method;use serde_json::json;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let org_id = "01HORG00000000000000000000".to_string();let add_path = format!("/integrations/{integration_id}/building-users");let _created: serde_json::Value = client .transport() .request_json(RequestSpec { method: Method::POST, path: &add_path, body: Some(&json!({ "user_id": user_ulid, "role": role_string })), extra_headers: &[("X-Org", org_id.clone())], ..Default::default() }) .await?;
let del_path = format!("/integrations/{integration_id}/building-users/{user_ulid}");client .transport() .request_json::<(), ()>(RequestSpec { method: Method::DELETE, path: &del_path, extra_headers: &[("X-Org", org_id)], ..Default::default() }) .await?;const buildingUsersUrl = `https://api.openapp.house/api/v1/integrations/${integrationId}/building-users`;const headers = { authorization: "Bearer v1_openapp_YOUR_SECRET", "content-type": "application/json", "x-org": orgId,};
const created = await fetch(buildingUsersUrl, { method: "POST", headers, body: JSON.stringify({ user_id: userUlid, role: roleString }),}).then((r) => r.json());
await fetch(`${buildingUsersUrl}/${userUlid}`, { method: "DELETE", headers: { authorization: "Bearer v1_openapp_YOUR_SECRET", "x-org": orgId, },});Body matches AddBuildingUserPayload (user_id + role strings; the role is the integration-scoped grant your deployment expects, often virtual_access:integration:{id}:resident). DELETE returns 204 with no body. Replace each fetch with AsyncClient.addBuildingUser / deleteBuildingUser once the Node façade exposes them.