Changelog
Every change to the API, dated. Additive changes land here on the day they ship; breaking ones appear here ninety days before they do.
2026-09-11
Ten webhook events, cancellation codes, occupancy field caps
Five new event keys — ticket.stale, property.notice.published, turn.task.stale, pm.stale and inspection.stale — join ticket.created, ticket.status_changed, turn.status_changed, turn.schedule_changed and vendor.hold; ten keys are subscribable. ticket.stale carries the Ticket and inspection.stale the Inspection; the other three carry a small inline dict with no read entity behind it; change is null on all five. PATCH /tickets/{ticket_id} publishes the seven-value cancellation_reason_code enum. POST /units/{unit_id}/move-in caps each party's first_name (80), last_name (80), email (150), phone (20) and external_id (120) and the top-level external_id (120); POST /units/{unit_id}/notice caps external_id (120). Over a cap is a 400 invalid_request before any write. Move-in parties are stored named leaseholders first; the response echoes the stored order.
2026-09-09
Turns
GET /turns and GET /turns/{turn_id}, scope read. A turn is the transition record — every transition lists, including a first-ever move-in. Filters property_id, unit_id, status and updated_since; status is Active / Completed / Cancelled and an unknown value is a 422 invalid_request. A turn carries projected_ready_on and a url to its transition page.
2026-09-09
Turn events carry the turn
turn.status_changed and turn.schedule_changed now carry entity_type turn, entity_id the turn id, and data = the same Turn object GET /turns/{turn_id} returns, in place of a unit object. change is unchanged. Receive the event, fetch the turn, same object.
2026-09-09
Occupancy ingest
POST /units/{unit_id}/notice and POST /units/{unit_id}/move-in. Scope write. Idempotency-Key and a provider slug are required. The response is an OccupancyRecord. There is no occupancy list or fetch.
2026-09-09
Inspections and meters
List and fetch for ops inspections (consulting-engagement walks excluded) and utility meters, plus GET /meters/{meter_id}/readings. Inspection status is Scheduled / In Progress / Completed; result is passed / failed / null. A reading has no url.
2026-09-09
Ticket writes
POST /tickets creates a ticket (status always Open). PATCH /tickets/{ticket_id} changes status; any status is reachable from any other. Both require Idempotency-Key and scope write. New code created_by_missing (422) when the key has no minting administrator.
2026-09-08
v1 published
Read access to tickets, properties, units, assets and vendors; bearer-key authentication with three scopes; keyset paging under {data, next_cursor, limit}; the shared error shape and its eighteen codes; five signed webhook events; create, list and delete for your own webhook subscriptions; and a public openapi.json.
2026-09-08
List filters
property_id, unit_id, status, updated_since and ticket_number on tickets; property_id, unit_id, status and updated_since on assets; property_id on units. An unsupported query parameter is now a 400 invalid_request instead of being ignored.
2026-09-08
url on every record, published enums, filter 422
url on all five objects; enums on Ticket.status, Ticket.priority and Asset.status; the per-resource parameters block in the document; 422 invalid_request for a status outside its enum.
2026-09-08
Vendor last_compliance_state
The hourly stored COI-compliance snapshot. unknown means never computed.
This is the whole history
v1 is new. When a webhook subscription can be paused or rotated over the API, they appear here as their own dated rows — not as edits to this one.
Deprecation
Ninety days. If we need to make a change that could break a working integration — the list is on versioning — it is announced on this page at least ninety days before it takes effect, and the old behaviour keeps working for that whole period.
- The announcement names what changes, when, and what to do instead.
- Additive changes need no notice, and are not breaking. Build so they cannot break you.
- A new major version would live at its own path. /api/v1 would not be switched under you.
- Your key's lifetime is your customer's decision: their administrator can revoke it at any time, from the same page they created it on. If your integration stops with a key_revoked, that is where to ask.
Watching this page
There is no email list yet. The reference and this page both change with the same publish, so if you diff openapi.json on a schedule you will see a structural change the day it lands.