Skip to main content

Error Codes

This page describes the response envelope used by every Secutix API endpoint and the registry of status codes you can switch on in your client.

Response envelope​

Every response — success and error, on every endpoint, at every HTTP status — uses the same JSON envelope with exactly three fields:

{
"status": "<code>",
"details": "<human-readable English message, null on success>",
"data": "<payload, null on errors>"
}
  • status is the only field a client should switch on. It's a stable, machine-readable code, lower-case snake_case.
  • details is meant for logs and developer-facing UIs. The wording can change without notice — do not parse it.
  • data carries the payload on 2xx and is null on every 4xx / 5xx.

The same envelope is returned by the API Gateway (e.g. 401 for a missing token), the authorizer (403), and the backend services — so a single parser handles all cases.

Success​

Every 2xx response uses the same status value:

{ "status": "success", "details": null, "data": { ... } }

Error codes​

The status field on 4xx / 5xx responses is drawn from the two registers below. The registry is intentionally open: new codes are added as new failure modes appear, under a documented naming convention. Treat unknown codes the same way you treat the generic code for the HTTP status you received.

Generic codes — one per HTTP family meaning​

HTTPstatusWhen
400bad_requestGeneric bad input (malformed payload, missing/invalid required field)
400validation_errorBean-validation constraint violation
400missing_parameterA required parameter is absent
400invalid_parameterA parameter has the wrong type, format, or enum value
401unauthorizedMissing or expired authentication token
403forbiddenValid token but insufficient permission for the resource
404not_foundEndpoint or resource id does not exist
405method_not_allowedHTTP method not supported on this path
409conflictThe request conflicts with the current state of the resource
412precondition_failedPre-condition (e.g. order state) not satisfied
422validation_errorSemantic validation failed (well-formed but unprocessable)
501not_implementedEndpoint is declared but not yet wired
502bad_gatewayUpstream system returned an error we propagate
503service_unavailableService temporarily unavailable (maintenance, circuit breaker)
500internal_errorUncaught server-side failure

Domain-specific codes​

A code earns its own slot in this table when a client can take a different action based on it than for a sibling error at the same HTTP status. Otherwise the generic code above is enough.

Conventions for new codes:

  • lower-case snake_case;
  • prefixed with the domain (cart_, contact_, payment_, shipment_, …);
  • the matching English message goes in details, never in status.

The seeded domain codes are tracked in tools/backlog/domain-specific-error-codes.md and added to the registry as they ship.

Contact​

HTTPstatusWhen
409contact_duplicate_emailPOST /contacts/individuals or /contacts/structures rejected because another contact already carries this email (trim + case-insensitive match). The error envelope's data field carries the full existing contact. Pass ?allowDuplicateEmail=true to bypass (family / B2B shared-inbox cases).

Parsing recipe​

const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
const body = await res.json();
if (body.status === "success") {
return body.data;
}
// Switch on the status code. Fall back to the HTTP status if the code is unknown.
switch (body.status) {
case "validation_error":
return showFormErrors(body.details);
case "not_found":
return show404();
case "unauthorized":
return redirectToLogin();
default:
return showGenericError(res.status, body.details);
}