Errors
Every error — including the ones raised before your request reaches the handler — is returned as a
Problem Details document with content type
application/problem+json. There is no second, older error shape to handle.
{
"type": "errors/not-found",
"title": "Leave request not found",
"detail": "No leave request matches the identifier provided.",
"status": 404,
"instance": "/api/v1/client/…",
"traceId": "00-4bf92f…-00f067aa0ba902b7-01"
}
| Field | Use it for |
|---|---|
type |
Branch on this. A stable slug that does not change with wording or locale. |
title / detail |
Human-readable, localized. Display them; never parse them. |
status |
Same value as the HTTP status code. |
instance |
The path that produced the error. |
traceId |
Quote this to support — it identifies your exact request in our traces. |
Error types
type |
Status | Meaning |
|---|---|---|
errors/bad-request |
400 | The request is malformed or fails validation. |
errors/forbidden |
403 | Authenticated, but not allowed to do this. |
errors/not-found |
404 | The resource does not exist, or is not yours to see. |
errors/conflict |
409 | The request conflicts with the current state. |
errors/module-disabled |
403 | No establishment of your perimeter has enabled the module this operation needs. One that has is enough for the operation to answer, on that establishment alone. |
errors/perimeter-unresolved |
403 | No establishment your access designates exists any more: all of them have been closed. Distinct from module-disabled, for a practical reason — there is nothing to subscribe to here. Your mandate has to be re-pointed at establishments that still exist, which only the customer company can do. |
errors/feature-not-in-plan |
403 | The company's subscription plan does not include this feature. |
errors/gone |
410 | The resource existed and no longer does — a stored file past its retention. Deliberately not 404: that would say it never existed, and you would look for a mistake in your own code. Ask for it again rather than retrying this one. |
errors/payload-too-large |
413 | The response we would have to send is too large to serve — a stored document beyond the size this API accepts to materialise. Not the same as quota/payload-too-large, which is about the body you sent: there is nothing to shrink on your side here. |
errors/service-unavailable |
503 | The resource exists and is yours to see, but a dependency we need to produce it did not answer. Retry after Retry-After seconds. |
errors/internal |
500 | Something failed on our side. Retry later; quote the traceId. |
scopes/insufficient |
403 | The token lacks a required scope — detail names it. See Authentication. |
quota/exceeded |
429 | Plan rate limit reached. See Rate limits. |
quota/payload-too-large |
413 | Request body exceeds your plan's cap. |
idempotency/key-required |
400 | The operation requires an Idempotency-Key. See Idempotency. |
idempotency/in-progress |
409 | The same key is already being processed. |
What we never put in an error
Error bodies carry no personal data. An unexpected failure is scrubbed to a generic errors/internal
rather than surfacing an internal message — so a 500 will not tell you much by design. That is what
traceId is for: it lets support find the full context without exposing it over the wire.
Retrying
| Status | Retry? |
|---|---|
400, 403, 404, 409 |
No. Fix the request. |
410 |
No — the resource is gone for good. Ask for a new one; retrying this identifier never succeeds. |
413 |
No — but read which one. quota/payload-too-large is your request body, so send less; errors/payload-too-large is a stored document we cannot serve, and there is nothing on your side to change. |
429 |
Yes, after Retry-After seconds. |
503 |
Yes, after Retry-After seconds. Cap your retries: the status does not say whether the dependency is coming back, so a resource that never returns would otherwise be retried forever. Open a ticket rather than looping. |
500, 502, 504 |
Yes, with exponential backoff. |
For a write that is not naturally idempotent, retry with the same Idempotency-Key — that is what
makes the retry safe. See Idempotency.