Error codes
Every response uses a uniform envelope, so clients key on success rather than branching on HTTP
status alone:
{ "success": false, "data": null, "error": { "code": "DISCUSSION_LOCKED", "message": "…" }, "meta": null }
Successful responses carry success: true and the payload in data (with pagination in meta).
Codes to handle
| Status | Code | Meaning & action |
|---|---|---|
| 400 | BAD_REQUEST | Malformed input. Fix the request. |
| 401 | UNAUTHORIZED | Missing/invalid API key, or an identity assertion that failed to verify. See Identity signing → debug. |
| 403 | IDENTITY_VERIFICATION_REQUIRED | Deployed tenant has no signing secret, or no assertion was sent. Mint a secret and sign. |
| 403 | FORBIDDEN | The key/principal lacks the required capability. |
| 403 | DISCUSSION_LOCKED | Write attempted on a locked discussion. |
| 403 | EDIT_WINDOW_EXPIRED | Comment edit attempted past its edit window. |
| 404 | NOT_FOUND | No such resource — expected when reading a discussion before its first comment. |
| 409 | CONFLICT | Uniqueness violation (e.g. duplicate report); IDEMPOTENCY_IN_PROGRESS for an in-flight retry. |
| 422 | UNPROCESSABLE_ENTITY | Syntactically valid but violates a business rule (e.g. reply past max depth); also idempotency-key body mismatch. |
| 429 | TOO_MANY_REQUESTS | Rate limited — honour the Retry-After header. |
| 5xx | INTERNAL / SERVICE_UNAVAILABLE | Transient — retry with backoff. |
Why 401 vs 403 IDENTITY_VERIFICATION_REQUIRED are split
They answer different questions: 403 IDENTITY_VERIFICATION_REQUIRED means "this tenant isn't
configured for verified identity yet" (mint the secret), while 401 means "you sent an assertion
and it didn't verify" (fix your signing). Branch on the code, not the message — messages may
change, but codes are part of the versioning contract.