Errors
Every error response has the same shape:
{
"error": {
"type": "insufficient_scope",
"message": "This key does not carry bookings:write",
"docs_url": "https://help.tatiya.space/developers/errors#insufficient_scope",
"request_id": "req_01JQ8Z…"
}
}
Branch on type. Never on message — messages are written for humans, and are expected to
change without notice.
| HTTP | type | Meaning |
|---|---|---|
| 400 | invalid_request | The body or query didn't validate. Carries fields[]. |
| 401 | unauthorized | The key is missing, malformed, expired, or revoked. |
| 403 | forbidden | Valid key, not allowed to do this. |
| 403 | insufficient_scope | The key lacks the scope this route needs. |
| 403 | feature_not_available | The space's tier doesn't include this. |
| 404 | not_found | No such resource in this key's space. |
| 409 | conflict | A state conflict. Bookings carry a booking_failure — see Bookings. |
| 429 | rate_limited | Slow down — see Retry-After in Making Requests. |
| 500 | internal_error | Ours. Retry with backoff, and quote the request_id if you reach out. |
Validation errors
invalid_request carries a fields[] array describing exactly what failed:
{
"error": {
"type": "invalid_request",
"message": "The request did not validate",
"fields": [
{ "path": "customer.email", "message": "Not a valid email", "code": "invalid_email" }
]
}
}
path is dotted and matches the shape of the request body, so a form can bind errors directly
without a separate mapping table.
not_found means "not in your space," too
A 404 doesn't distinguish "this id doesn't exist" from "this id exists, but not in the space
your key is scoped to." That's deliberate — the two cases should be indistinguishable to a caller,
the same way an unfamiliar visitor to a private page shouldn't learn anything from the difference
between "not found" and "not yours."