Skip to main content
The Orgo API returns errors as JSON. Two envelope shapes exist — one for general errors, one for validation errors. Both carry the HTTP status in the body as well as in the response status line, so you can log either reliably.

General error envelope

For most errors (400, 401, 403, 404, 409, 500):
Some errors include additional context (e.g., the conflicting resource ID on a 409) under a context or meta field — these are documented per endpoint.

Validation error envelope (422)

When the API rejects a request because field-level validation failed, the response includes a violations array enumerating each failed field:
Iterate violations[] to surface each error next to the right form field. code is a stable Symfony validator UUID — useful if you want to localize the message without parsing the English text.

Status codes

The request is malformed at the HTTP/JSON level: invalid JSON syntax, wrong Content-Type, missing required query parameter, unknown enum value.
Retry? No. The same request will fail again. Inspect detail and fix.
The auth header is missing, malformed, or carries an expired/revoked token. JWT might have expired (refresh it); Api-Token might have been revoked.
Retry? Yes, after refreshing the token or re-authenticating. If a fresh token still fails, the tenant might be wrong — see Tenancy.
You’re authenticated, but your user (or the API token’s owner) lacks the permission required for this action.Common reasons:
  • The token is read-only and you sent a write
  • The user has HR_LOCAL but the resource is in a different local center
  • The endpoint requires ADMIN_TENANT and the user is HR_LOCAL
Retry? No. Have an admin grant the missing permission, or use a different token.
The resource does not exist, OR exists but belongs to a different tenant than the one your auth is scoped to. Orgo returns 404 (not 403) in the second case so the absence of the resource is indistinguishable from “exists but forbidden” — preventing tenant-existence leaks.
Retry? No. Verify the ID/URL and the tenant host.
The request would create a conflict with the current state of the resource. Two common causes:
  • Optimistic locking: another writer updated the record between your read and your write. Refetch and retry.
  • Illegal state transition: e.g., trying to mark a contract as signed twice, or transition an adhesion to a state that is not reachable from its current state.
  • Duplicate identifier: e.g., creating a resource whose external ID already exists.
Retry? Sometimes. For optimistic-lock collisions: refetch, reconcile your changes, retry. For illegal state transitions: no — fix the workflow. For duplicate IDs: no — use a different identifier or update the existing resource.
The request is well-formed but one or more fields failed validation (required, format, length, custom rules).
Retry? No. Iterate violations[], surface each error next to the right form field, let the user correct, and resubmit.
You hit the per-endpoint rate limit (usually 20/min on write-heavy endpoints like login or send-email).
The response includes a Retry-After header (seconds).Retry? Yes, after Retry-After. See Rate limits.
Something went wrong inside Orgo. The detail may be generic (“An error occurred”) to avoid leaking internals.Retry? Yes, with exponential backoff. If a 500 reproduces on the same call repeatedly, contact support with the request ID from the response headers.
Load balancer, application server, or upstream dependency is unreachable.Retry? Yes, with exponential backoff (start ~1s, double up to ~30s, give up after ~5 minutes).

Retry strategy

A safe default for any integration:
Do not retry:
  • 400, 401, 403, 404, 422 — retrying produces the same failure
  • 409 from illegal state transitions or duplicate IDs — retrying still conflicts
  • 409 from optimistic locks — refetch first, then retry once (not in a tight loop)

Logging tips

Save the request ID from response headers (when present) — it lets support trace the exact request in our logs. The body’s status field mirrors the HTTP status, so you can log just the response body and recover the status from JSON without needing two fields.
  • Authentication — what 401 and 403 mean per auth method
  • Tenancy — why a 404 may actually be a tenant mismatch
  • Rate limits — how to avoid 429 in the first place