Skip to main content
Every error in this API — with one exception, noted below — is an RFC 7807 problem document, served as application/problem+json:
Branch on code, never on type or the wording of detail. code is the contract; title and detail are for people and we reserve the right to rewrite them. instance identifies this one occurrence — it is an identifier, not a URL — and quoting it is the fastest way for your Maat contact to find the request in our logs.

The codes

Two codes carry a typed extension member: validation_failed adds errors[] ({ field, code } per rejected field — never the value you sent), and conflict adds conflicts[] (every colliding date, untruncated). Parse those, not the prose.

One refusal, several causes — on purpose

Some errors deliberately do not say which of several checks failed. An unknown key, a revoked key and a wrong secret all answer the same 401; a sandbox/production mismatch and a workspace that does not resolve answer the same 403; a listing that does not exist and one that belongs to somebody else answer the same 404. Distinguishing them would let anyone enumerate credentials, tenants or another customer’s inventory. If you are stuck on one of these, the answer is a conversation with your Maat contact, not more requests.

The one exception

The token exchange (POST /v1/token) answers its refusals with a plain { "message": … } body rather than a problem document — you meet it once, at the start of a session. An unexpected fault there is a problem document like everywhere else.
The type URIs are stable identifiers, and code is what you should branch on. Do not fetch a type URI at runtime or assume it serves content.