> ## Documentation Index
> Fetch the complete documentation index at: https://developer.maatstays.wtf/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> One error shape, nine stable codes, and what to do about each.

Every error in this API — with one exception, noted below — is an
[RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) problem document, served as
`application/problem+json`:

```json theme={null}
{
    "type": "https://developer.maatstays.wtf/errors/conflict",
    "title": "Conflict",
    "status": 409,
    "detail": "These nights are already booked or held on Maat, so the block was not applied: 2026-09-02, 2026-09-03.",
    "instance": "urn:maat:request:3b1f7a90-0d4c-4d4e-9b2a-6c1f0a2e5d33",
    "code": "conflict",
    "conflicts": ["2026-09-02", "2026-09-03"]
}
```

**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

| `code`                     | Status | What happened                                                         | What to do                                                                                                                                                                                    |
| :------------------------- | :----- | :-------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `validation_failed`        | 400    | The payload does not match the published schema.                      | Read `errors[]` — it names each rejected field and the rule it broke. Fix the payload; do not retry unchanged.                                                                                |
| `unauthorized`             | 401    | No usable token: missing, malformed, expired, or its key was revoked. | Mint a fresh token and retry once. If it persists, your key has been revoked — talk to your Maat contact.                                                                                     |
| `workspace_scope_mismatch` | 403    | The token's environment does not match the workspace it addresses.    | You are using a sandbox token where a production one is needed, or the reverse. Check which key you exchanged. Never retry unchanged.                                                         |
| `property_not_found`       | 404    | No such property in the workspace your key addresses.                 | Check the `listing_id` or `provider_id` you sent. Nothing was written.                                                                                                                        |
| `conflict`                 | 409    | The nights collide with a Maat booking or a live hold.                | Act on `conflicts[]` — the complete list of colliding dates. Re-push a range that excludes them, or leave the block off. Nothing was written.                                                 |
| `rate_limited`             | 429    | Too many requests for this key.                                       | Wait `Retry-After` seconds, then resume. See [Rate limits](/guides/rate-limits).                                                                                                              |
| `internal_error`           | 500    | Our fault.                                                            | Retry an idempotent request with backoff. If it persists, quote `instance` to your Maat contact. Use `GET /v1/blocks` to check whether a push landed.                                         |
| `not_enabled`              | 501    | The contract is published and not yet enabled for this workspace.     | Nothing was written and nothing will be delivered. Expected in production before launch — your request was authenticated and validated in full, so a `501` means your integration is correct. |
| `service_unavailable`      | 503    | A capability we need is not configured on our side.                   | Not a rejection of your request; nothing was written. Retry with backoff.                                                                                                                     |

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.

<Note>
  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.
</Note>
