Access Codes
Access-code and smart-lock API behavior in NapX PMS.
Access Codes
NapX PMS provisions guest access codes through the smart-lock adapter while keeping tenant isolation enforced by PostgreSQL Row-Level Security.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /v1/smart-locks/connect-webview | Creates a tenant-scoped Seam Connect Webview for smart-lock onboarding |
| GET | /v1/smart-locks/connect-webview/:id | Polls the tenant-owned Seam Connect Webview until it reaches a terminal state |
| POST | /v1/smart-locks/connect-account | Stores the connected Seam account and triggers a device sync retry-safe flow |
| GET | /v1/access-codes | Lists property-scoped access-code metadata and supports optional lock-device filtering |
| GET | /v1/access-codes/:id | Returns access-code metadata without PIN storage fields |
| GET | /v1/access-codes/:id/code | Returns the stored PIN for one access code |
| GET | /v1/reservations/:id/access-codes | Lists reservation access codes without exposing the stored PIN field |
| POST | /v1/reservations/:id/access-codes/retry | Re-runs provisioning for failed reservation access codes |
Smart-Lock Onboarding
POST /v1/smart-locks/connect-webviewcreates the Seam Connect Webview and records its id against the authenticated tenant.GET /v1/smart-locks/connect-webview/:idis tenant-scoped and still returns the finalauthorizedstate even if the webhook saves the connected account before the next client poll.POST /v1/smart-locks/connect-accountpersists the connected account after verifying the authorized webview state, and a repeated call with the same account id retries device sync if the first sync attempt failed.
Response Shape
GET /v1/access-codes/:idreturns access-code metadata such assyncStatus,startsAt,expiresAt,lockDeviceId, andseamAccessCodeId.GET /v1/access-codes?propertyId=<uuid>&lockDeviceId=<uuid?>returns property-scoped access-code metadata rows and never returns the plain PIN field.GET /v1/access-codes/:id/codereturns{ code: string | null }.GET /v1/reservations/:id/access-codesreturns an array of access-code metadata rows.POST /v1/reservations/:id/access-codes/retryreturns the reservation's active access-code rows after retry completes.
Security Model
- Every request requires
Authorization: Bearer <session-token>. - Tenant context is derived from validated auth claims, not from a client-supplied
x-tenant-idheader. - List and detail routes never expose the stored
codefield. - Plain PIN retrieval is limited to the dedicated
/v1/access-codes/:id/coderoute.
Error Handling
404 Not Foundwhen the access code or reservation does not exist for the tenant.401 Unauthorizedwhen the bearer token is missing or invalid.403 Forbiddenwhen the authenticated session lacks valid tenant scope for the requested record.GET /v1/reservations/:id/access-codesreturns200 []when the reservation currently has no active access codes.
Retry Behavior
- Retry only targets rows currently marked
syncStatus = error. - Older duplicate error rows for the same lock device are soft-deleted during retry.
- When reprovisioning is possible, the current error row is soft-deleted and a replacement row is created for the same reservation and lock device.
- When the lock device can no longer be reprovisioned, the latest error row remains active so the failure is still visible and retryable.
- Already-synced rows are not recreated.
- Superseded or soft-deleted rows are not returned by the detail, list, or PIN lookup endpoints.
Operational Notes
- Access codes are generated per connected lock device on the reservation's property or space.
- Failed provisioning attempts are marked with
syncStatus = errorand can be retried later. - Generated guest PINs use the full
0000-9999four-digit range. - Seam webhook events are signature-verified before sync-state updates when
SEAM_WEBHOOK_SECRETis configured. - In non-production environments without
SEAM_WEBHOOK_SECRET, the webhook endpoint accepts unsigned JSON payloads. - In production, the webhook endpoint returns
503 Service UnavailableuntilSEAM_WEBHOOK_SECRETis configured.
Example
GET /v1/access-codes/9f5aab77-2f7d-4d30-a4eb-7ae89b030d49/code
Authorization: Bearer <session-token>
See the API reference for the detailed endpoint contract.