Integrate OpenApp with your existing software
Hotels, campuses, offices, short-term rentals, and locker / parcel operators already run systems of record — property management (PMS/VRMS), student information (SIS), workplace (IWMS), or custom parcel software. OpenApp is designed as an API-first access layer on top of that stack: your software stays authoritative for bookings and identities; OpenApp models who may open which door, when, and how guests are invited.
See Model by sector for the full sector list and which primary system pairs with each.
Integration pattern
Section titled “Integration pattern”Your system (PMS / SIS / IWMS / custom) │ webhook or scheduled job ▼OpenApp HTTP API or SDK │ invitations · entity actions · scripting ▼Doors, gates, intercom portals, auditTypical responsibilities:
| Your system | OpenApp |
|---|---|
| Reservation / enrollment dates | Time-bound access invites |
| Room or unit identifier | Portal ids, entity ids, zones (mapped once at setup) |
| Checkout / departure event | Disable or delete invite; optional switchable.close |
| Staff directory (optional) | Building users / apartment residents APIs |
Sector examples
Section titled “Sector examples”Short-term rental (VRMS / PMS)
Section titled “Short-term rental (VRMS / PMS)”On check-in (webhook): create an access invite with valid_from / valid_to aligned to stay dates; send the guest the public invite URL or deep link.
On checkout: PUT to disable the invite or DELETE when the link must not be reused.
Pair with Public Access and the STR portfolio playbook.
Hotel (PMS)
Section titled “Hotel (PMS)”Same invite pattern as STR, often with additional staff roles and lobby portals. See Boutique hotel playbook for unified orchestration alongside room-lock vendors.
Campus (SIS)
Section titled “Campus (SIS)”Map dorm or building to an OpenApp org or sub-org. Provision roles via Apartment residents or org user APIs when the SIS emits enrollment changes.
Use OpenApp Scripting for bulk term rollover if many buildings share one template.
Office (IWMS)
Section titled “Office (IWMS)”IWMS often owns badging and occupancy; OpenApp can orchestrate physical actuators (doors, lifts, parking gates) when IWMS events fire. Prefer read-only discovery agents first; gate switchable.open behind IWMS-approved states.
Parcel / locker matrix
Section titled “Parcel / locker matrix”Model each compartment as an entity (or scripted matrix). Release on pickup code validation in your app → POST .../actions/switchable.open on the compartment entity.
Minimal webhook handler (Python)
Section titled “Minimal webhook handler (Python)”SDK
import osfrom datetime import datetime, timezone
from openapp_sdk import AsyncClient
client = AsyncClient(os.environ["OPENAPP_API_KEY"])INTEGRATION_ID = os.environ["VIRTUAL_ACCESS_INTEGRATION_ID"]LOBBY_PORTAL_ID = os.environ["LOBBY_PORTAL_ID"]
async def on_check_in(reservation_id: str, arrival: datetime, departure: datetime): await client.integrations.create_access_invite( INTEGRATION_ID, portal_ids=[LOBBY_PORTAL_ID], name=f"Stay {reservation_id}", valid_from=arrival.astimezone(timezone.utc).isoformat(), valid_to=departure.astimezone(timezone.utc).isoformat(), max_uses=50, )import { AsyncClient } from "@tomers/openapp-sdk";
const client = new AsyncClient(process.env.OPENAPP_API_KEY!, { org: orgId });
async function onCheckIn( reservationId: string, arrival: Date, departure: Date,): Promise<void> { await client.integrations.createAccessInvite(integrationId, { portal_ids: [lobbyPortalId], name: `Stay ${reservationId}`, valid_from: arrival.toISOString(), valid_to: departure.toISOString(), max_uses: 50, });}use chrono::{DateTime, Utc};use openapp_sdk::Client;use serde_json::json;
async fn on_check_in( client: &Client, integration_id: &str, lobby_portal_id: &str, reservation_id: &str, arrival: DateTime<Utc>, departure: DateTime<Utc>,) -> Result<(), openapp_sdk::SdkError> { let body = json!({ "portal_ids": [lobby_portal_id], "name": format!("Stay {reservation_id}"), "valid_from": arrival.to_rfc3339(), "valid_to": departure.to_rfc3339(), "max_uses": 50, }); client .integrations() .create_access_invite(integration_id, &body) .await?; Ok(())}func onCheckIn( ctx context.Context, client *openapiclient.APIClient, orgID, integrationID, lobbyPortalID string, reservationID string, arrival, departure time.Time,) error { body := openapiclient.NewCreateIntegrationAccessInviteRequest( []string{lobbyPortalID}, fmt.Sprintf("Stay %s", reservationID), ) body.SetValidFrom(arrival.UTC().Format(time.RFC3339)) body.SetValidTo(departure.UTC().Format(time.RFC3339)) body.SetMaxUses(int32(50)) _, httpResp, err := client.IntegrationsAPI.CreateIntegrationAccessInvite(ctx, integrationID). XOrg(orgID). CreateIntegrationAccessInviteRequest(*body). Execute() if err != nil { return err } defer httpResp.Body.Close() return nil}Adjust paths to match your deployment; confirm create_integration_access_invite in the API reference for the latest request schema.
Python (HTTP API)
import osfrom datetime import datetime, timezone
import httpx
API_BASE = os.environ["OPENAPP_API_BASE"]API_KEY = os.environ["OPENAPP_API_KEY"]ORG = os.environ["OPENAPP_ORG_ID"]INTEGRATION_ID = os.environ["VIRTUAL_ACCESS_INTEGRATION_ID"]LOBBY_PORTAL_ID = os.environ["LOBBY_PORTAL_ID"]
async def on_check_in(reservation_id: str, arrival: datetime, departure: datetime): body = { "portal_ids": [LOBBY_PORTAL_ID], "name": f"Stay {reservation_id}", "valid_from": arrival.astimezone(timezone.utc).isoformat(), "valid_to": departure.astimezone(timezone.utc).isoformat(), "max_uses": 50, } async with httpx.AsyncClient() as http: await http.post( f"{API_BASE}/integrations/{INTEGRATION_ID}/access-invites", headers={ "authorization": f"Bearer {API_KEY}", "content-type": "application/json", "x-org": ORG, }, json=body, )HTTP proof (curl)
Section titled “HTTP proof (curl)”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 '{ "portal_ids": ["'"${PORTAL_ID}"'"], "name": "PMS stay 4821", "valid_from": "2026-06-01T15:00:00Z", "valid_to": "2026-06-05T11:00:00Z", "max_uses": 20 }' \ "${OPENAPP_API_BASE}/integrations/${INTEGRATION_ID}/access-invites"The response includes invite_token for guest URLs — distribute through your PMS guest messaging, not in public logs.
Related docs
Section titled “Related docs”- AI agents overview — API vs SDK vs scripting.
- Build an access-control agent — keys,
X-Org, entity actions. - Integrations SDK — portals and invite maintenance.
- OpenAPI bundle for codegen and contract tests.