Error Handling
The API uses standard HTTP status codes and returns consistent JSON error bodies for all failure cases.HTTP status codes
| Code | Meaning | Common cause |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource was created |
204 | No Content | Resource was deleted |
400 | Bad Request | Malformed request body |
401 | Unauthorized | Missing or invalid Authorization header |
403 | Forbidden | Token valid but insufficient permissions |
404 | Not Found | Resource does not exist or belongs to another tenant |
422 | Unprocessable Entity | Validation failed (see errors field) |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
Error response body
All error responses return a JSON body. The structure varies by error type.Validation error (422)
errors object maps field names to an array of human-readable messages.
Authentication error (401)
Not found (404)
Generic server error (500)
Handling errors in code
Common mistakes
Missing X-Tenant header
Missing X-Tenant header
Returns
401 or 404 depending on the endpoint. Always include X-Tenant on resource endpoints.File already in use
File already in use
When creating a certificate, the
file_uuid must reference a file that has not yet been attached to another certificate. Files track a used_at timestamp — once set, the file cannot be reused.Wrong UUID format
Wrong UUID format
All UUID fields must be in standard v4 format:
550e8400-e29b-41d4-a716-446655440000. Passing an integer ID where a UUID is expected returns 422.Referencing entities from another tenant
Referencing entities from another tenant
If you pass a
course_uuid or student_uuid that belongs to a different tenant, the API returns 422 with "The selected ... is invalid." — the entity lookup is always tenant-scoped.