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.