Errors

Every error response from /api/v1/* carries a stable, machine-readable code field. Partners filter on code, not on HTTP status (statuses are shared across multiple codes) and not on the message (which is localized). The code space is append-only: a code that ships never gets renamed, renumbered, or removed.

Envelope

A typical 400 response:

json
{
"code": "VALIDATION_FAILED",
"message": "Name is required.",
"errors": { "name": ["Name is required."] }
}
  • code: one of the values in the catalog below. Filter on this.
  • message: a human-readable description, localized to the caller’s Accept-Language (defaults to hr). Do not parse this programmatically.
  • errors: present on VALIDATION_FAILED responses. A dictionary keyed by field name with an array of localized messages per field.

Server errors (HTTP 500) omit the errors dictionary and carry a generic message. Retry with back-off; if the error persists, contact support with the request id (visible in the response X-Request-Id header where present).

Catalog

CodeHTTPWhen it firesPartner response
VALIDATION_FAILED400Request body failed validation, or a required header is missing.Inspect the errors dictionary. Surface field-level messages to the end user.
UNAUTHORIZED401The API key is missing, malformed, or revoked.Check the Authorization header. Re-issue the key if it was revoked.
API_ACCESS_NOT_ENABLED402The target company does not have the ApiAccess subscription feature.Upgrade the company to Enterprise, or add the ApiAccess add-on, in the billing settings.
FORBIDDEN403Authenticated, but the key’s issuing user lacks permission for the operation in this scope.Check the acting user’s role in the target company. Re-issue the key as an admin.
NOT_FOUND404The target resource does not exist or has been deleted.Verify the id. The resource may have been removed by another actor.
CONFLICT409Duplicate resource, stale precondition, or an idempotency-key replay with a different body.Reconcile state. Retry may succeed with a different payload, or may require no-op.
RATE_LIMIT_EXCEEDED429Per-key rate limit window (per-second, per-hour, or per-day) was exceeded.Back off per the Retry-After header. See Rate limits.
KEY_REVOKED401Reserved for a future custom challenge handler. Not currently emitted.Pre-wire your handler. Today the revoked-key flow returns a bare HTTP 401.
INTERNAL_ERROR500An unhandled server error.Retry with exponential back-off. If the error persists, contact support.

Append-only guarantee

Once shipped, a code stays in the catalog forever, even if its emitter is deleted. Partners can rely on their code switch statements never silently breaking because locco renamed a value. If behavior around a code changes (different HTTP status, new constraint) it is called out in the changelog; the code string itself remains stable.

Partners are encouraged to handle unknown codes defensively: if a new code ships before your client is updated, treat it as a generic failure (probably INTERNAL_ERROR-shaped) and log the raw response for later review rather than crashing.