Skip to content
OpenAppPhysical access, simplified
Login

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. Office corridors, campus stairs, and fire doors need a door-by-door class; many leaves must not be electrically locked via OpenApp. See Life safety and egress.

See Model by sector for the full sector list and which primary system pairs with each.

Your system (PMS / SIS / IWMS / custom)
│ webhook or scheduled job
OpenApp HTTP API or SDK
│ invitations · entity actions · scripting
Doors, gates, intercom portals, audit

Typical responsibilities:

Your systemOpenApp
Reservation / enrollment datesTime-bound access invites
Expected guest occupancy / sharing policymax_devices for unique guest browsers/devices; max_uses for total invite usage
Room or unit identifierPortal ids, entity ids, zones (mapped once at setup)
Checkout / departure eventDisable or delete invite; optional switchable.close
Staff directory (optional)Building users / apartment residents APIs

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. Set max_devices from the reservation occupancy when one booking should support several family or group members—for example, 4 for a four-person booking. Set max_uses separately if total openings or redemptions must also be capped.

The browser stores a persistent per-device identifier, so forwarding the URL to an additional device consumes another device slot while refreshing or reopening it on an already registered device does not. This preserves frictionless shared use for the booked group while limiting accidental or abusive forwarding.

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.

Same invite pattern as STR, often with additional staff roles and lobby portals. See Boutique hotel playbook for unified orchestration alongside room-lock vendors.

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.

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.

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.

SDK

import os
from 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,
)

Adjust paths to match your deployment; confirm create_integration_access_invite in the API reference for the latest request schema.

Python (HTTP API)

import os
from 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_devices": 4,
"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 API (curl)

Terminal window
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_devices": 4,
"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.