Skip to main content

Errors

AISafe API errors use a consistent envelope.

Error envelope

Error responses use this shape:

{
"detail": "Human-readable error message"
}

The detail field is a human-readable string explaining what went wrong. Clients should dispatch on the HTTP status code, since the API may reword the detail message text without notice.

# Example: 404 response
HTTP/1.1 404 Not Found
Content-Type: application/json

{"detail": "Assessment not found"}

Status codes

StatusWhenWhat to do
400Malformed input or business-rule validation failureInspect the message, fix the request, and resubmit. Do not auto-retry.
401Missing, expired, invalid, or revoked credentialsRe-authenticate. For API keys, treat as permanent until the key is rotated.
403Authenticated but not authorized: role too low or scope missingDo not retry with the same principal. Use a key with different scopes, or escalate.
404Resource not found, or cross-organization access collapsed to not-foundTreat as absent. Do not infer tenant existence from a 404.
409State conflict: resource cannot transition from its current state, or a uniqueness constraint firedRe-fetch the resource and reconcile before retrying.
422Semantic validation failure: request shape was valid but contents were rejectedFix the payload and resubmit.
429Rate-limited: the response carries a Retry-After headerBack off for at least the advertised interval, then retry.
500Unexpected server errorRetry only for idempotent operations, and only with backoff. Contact support for repeated failures.

The 404-vs-403 rule

AISafe returns 404 when a caller tries to access a resource belonging to an organization they do not belong to. Returning 403 would leak the existence of the resource, and of the other tenant, to a caller who can guess an ID. The rule applies across assessments, findings, reports, artifacts, and other resources scoped to an organization.

Implication for clients: a 404 means "this resource does not exist or you do not have access." Do not infer that the resource exists but is forbidden.

Rate-limit errors

A 429 response includes:

  • Retry-After header: seconds to wait before retrying.
  • Body: {"detail": "Rate limit exceeded. Retry after <N>s."} (text is not a contract).

Clients must honor the Retry-After header and implement exponential backoff for repeated 429s.

Auth-specific exceptions

Two auth cases return structured JSON alongside the human detail:

  • Unverified accounts: POST /api/v1/auth/login against a pending user returns 403 with {"code": "EMAIL_NOT_VERIFIED"} so clients can offer a "resend confirmation" flow.
  • 2FA required: POST /api/v1/auth/login with a password-correct user that has TOTP enabled returns {"requires_2fa": true, "partial_token": "..."} instead of the usual 401.

Other auth failures use the plain {"detail": "..."} envelope.