Skip to main content
There are two numbers on this API and only one of them is a version you pin. info.version is a publication date, not a release you can request. There is no version header, no Accept parameter and no query string that selects one — the path segment is the whole mechanism, so two integrations pointed at /v1 are always looking at the same contract.

What changes without notice

These are additive, they ship whenever they are ready, and each one is recorded in the changelog:
  • a new operation, or a new optional query parameter on an existing one;
  • a new optional member on a request body;
  • a new member on a response body;
  • a new member on an existing enum — a new code, a new status, a new event_type;
  • a new webhook event type, which reaches you only if you subscribe to it.
Your client must tolerate all five. Concretely: ignore response members you do not recognise rather than failing on them, treat an unrecognised code as its HTTP status class, and treat an unrecognised enum value as “something newer than my client” rather than as corrupt data. Nothing in this document is additionalProperties: true, so the reverse is not true — a field you invent is still a 400. Read that literally when you generate a validator. Most response objects here are published closed (additionalProperties: false), and a response object is closed as published: a new member arrives in the schema in the same release it arrives on the wire. So regenerate against the current document rather than pinning an old copy, and do not reject an unrecognised member at runtime — the closedness describes what we had published when you generated, not a promise that nothing will ever be added.

What does not change without notice

Removing an operation, a member or an enum value; renaming any of them; narrowing a type; tightening a validation rule; or changing what a status code means. None of that happens inside /v1. This is the promise from the first production key onward. The corrections dated 2026-09-07 and 2026-09-30 predate that and are named in the changelog; nothing has changed under an integration since. A change of that kind gets a new major — /v2 — served alongside /v1 for a stated overlap period, so nothing you have built stops working on the day it appears. The length of that overlap is a commitment we have not published yet; it will be stated here before the first one exists, and no major has ever been retired.

Deprecation, when it happens

Nothing in this contract is deprecated today, and nothing carries a retirement date. When something is:
  • the operation, parameter or member is marked deprecated: true in the OpenAPI document, so a generated client warns at compile time rather than at three in the morning;
  • responses from it carry a Sunset header giving the date after which it stops answering, in HTTP-date form;
  • the changelog carries the entry, naming the replacement.
A deprecated thing keeps working until its Sunset date. It does not start refusing, and it does not start returning less.

How you hear about a change

The changelog is the record, and it is the only one — there is no email list, no RSS feed and no contract.changed webhook today. If you want to watch for changes mechanically, the OpenAPI document is served at a stable URL and its info.version moves whenever it does.

Using this document

The specification and these guides are published so you can build an integration against Maat Stays. What your integration may do with the platform, and with anything it receives from it, is set by the Developer Terms your workspace signed before its first key was issued. They are not published at a public URL today, which is why this document carries no termsOfService: pointing at one that does not exist would be worse than pointing at nothing. The copy that binds you is the one your workspace signed, in your own Maat account.