The exact inventory of endpoints, event types and scopes is shared with integrators against the runtime they will call — it grows with the product, so we do not freeze a number here.
Versioned REST at /api/public/pms/v1
The specification is generated from the routes the runtime actually serves, and a parity gate fails the build when a route and its documentation disagree.
- OpenAPI
- Published by the runtime itself, not maintained by hand on the side.
- Versioning
- The version is part of the path. A breaking change creates a new version; the previous one keeps answering.
- Resources
- Properties, reservations, guests, folios, payments, POS, housekeeping, maintenance, financial data and tax.
- Formats
- JSON in, JSON out. Amounts are integers in minor units with the currency declared.
OAuth 2.0 client credentials
A credential is issued inside the product by someone who can already see the data it will read. There is no public self-service signup.
- Grant
- client_credentials. The token is opaque and expires in one hour.
- Secret
- Shown once, stored hashed, and not recoverable by design.
- Rotation
- Generate a new secret and the previous one stays valid for 24 hours, so a partner switches without downtime.
- Revocation
- Suspend or revoke a credential and every token minted from it stops working.
Two questions, two mechanisms
“Can this client read reservations?” is a scope. “Can it read reservations of THIS property?” is a grant. Confusing the two is how a partner ends up seeing a whole portfolio.
- Scopes
- Per resource and per operation, split between read and write. An unknown scope is denied, never ignored.
- Property grants
- Explicit per property. No grant means no property — never “all”.
- Tenant
- Derived from the token. There is no tenant parameter in the API to get wrong.
- Denials
- Stable, distinguishable reasons: scope denied, property denied, property required.
Incremental reads that do not lose a row
A cursor over a timestamp alone breaks the moment two facts share a millisecond. Ours carries the identifier as well, so a page boundary inside a single instant is still exact.
- updatedSince
- Ask for what changed since your last successful read.
- Composite cursor
- Ordered by instant and identifier, so the cut inside one instant loses and duplicates nothing.
- Unreadable cursor
- Answered with an error, never by silently restarting from the first page.
- Stable errors
- Invalid cursor, timestamp, business date and identifier each have their own public code. Database errors never cross the boundary.
Signed delivery, with the failure states visible
Operational facts are pushed as they happen. What matters on the receiving end is not the happy path — it is knowing exactly what was delivered and what was given up on.
- Signature
- HMAC-SHA256 over the timestamp and the raw body, sent as t=<unix>,v1=<hmac>, with a 300-second tolerance. The exact material is in the specification.
- Replay protection
- A signature captured in transit cannot be re-sent later as if it were new.
- Retries
- Automatic redelivery with backoff, manual redelivery on demand, and a dead-letter state you can see.
- Destination safety
- The target is validated on every attempt, including after DNS resolution, so an endpoint cannot be pointed at internal infrastructure.
- Delivery log
- Every attempt, response code and outcome, per endpoint.
Retry safely, and know your quota
An integration that cannot retry is an integration that duplicates. Writes are idempotent and quotas are shared across replicas.
- Idempotency
- Send a key with a write and a repeat returns the original result. The same key with a different body is rejected, not silently accepted.
- Rate limit
- Per credential, counted in shared storage so replicas do not each grant the full quota. Headers carry the limit, the remainder and the reset.
- Degraded mode
- If shared counting is unavailable, the limit falls back to a weaker local one — and the response says so in a header instead of pretending.
- Errors
- A stable public code and a human message. No internal identifiers, no stack traces.
What the API refuses to do
Some guarantees are best expressed as refusals — they cannot be misconfigured away.
- No card data
- Card numbers and security codes are rejected at the boundary. The API never becomes a place they could be stored.
- No cross-property reads
- A request outside the granted properties is denied with its own reason, not filtered to an empty list.
- No leaked internals
- Database and infrastructure errors are translated before they reach a client.
- Audit trail
- Credential lifecycle and API activity are recorded against a validated taxonomy.
Getting started
Four steps, all inside the product. Nothing here is self-service on the public site.
- Create a credentialIn the PMS, under Integrations & API. The secret is shown once.
- Grant scopes and propertiesOnly the resources and the properties this integration needs.
- Get a tokenExchange the credential for a one-hour access token.
- Read the specificationThe OpenAPI document describes every endpoint, payload and error you can receive.
Honest limits
- No public developer portal or sandbox signup — credentials are issued inside the product.
- Event delivery is HTTP webhooks; there is no WebSocket stream.
- No partner marketplace of downloadable connectors and no certified connectors.
- Current maturity targets a controlled pilot, not a global rollout.
Building an integration?
Tell us what you need to read or write. We share the specification and the credential scope that fits.