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
| Status | When | What to do |
|---|---|---|
| 400 | Malformed input or business-rule validation failure | Inspect the message, fix the request, and resubmit. Do not auto-retry. |
| 401 | Missing, expired, invalid, or revoked credentials | Re-authenticate. For API keys, treat as permanent until the key is rotated. |
| 403 | Authenticated but not authorized: role too low or scope missing | Do not retry with the same principal. Use a key with different scopes, or escalate. |
| 404 | Resource not found, or cross-organization access collapsed to not-found | Treat as absent. Do not infer tenant existence from a 404. |
| 409 | State conflict: resource cannot transition from its current state, or a uniqueness constraint fired | Re-fetch the resource and reconcile before retrying. |
| 422 | Semantic validation failure: request shape was valid but contents were rejected | Fix the payload and resubmit. |
| 429 | Rate-limited: the response carries a Retry-After header | Back off for at least the advertised interval, then retry. |
| 500 | Unexpected server error | Retry 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-Afterheader: 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/loginagainst a pending user returns 403 with{"code": "EMAIL_NOT_VERIFIED"}so clients can offer a "resend confirmation" flow. - 2FA required:
POST /api/v1/auth/loginwith 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.
Related
- API conventions: base URLs, pagination, rate limits
- Authentication: API keys, scopes, and session JWTs
- API Reference: per-endpoint documentation