HTTP Status Code Mapping¶
This page documents how Curaway maps HTTP status codes to specific API behaviors. Every response is wrapped in the standard response envelope and error responses include machine-readable error codes.
Status Code Reference¶
200 OK¶
The request succeeded and the response body contains the requested data.
| Scenario | Example |
|---|---|
| Retrieve a case | GET /api/v1/cases/case-abc-123 returns the case object |
| List providers | GET /api/v1/providers/?country=DE returns a paginated provider list |
| Search providers | POST /api/v1/search/ returns semantically matched providers |
| Get FHIR resource | GET /api/v1/fhir/Patient/pat-001 returns the FHIR Patient resource |
| Update a case | PATCH /api/v1/cases/case-abc-123 returns the updated case |
201 Created¶
A new resource was successfully created. The response body contains the newly created resource, including its server-generated id and created_at timestamp.
| Scenario | Example |
|---|---|
| Create a patient | POST /api/v1/patients/ returns the new patient record |
| Create a case | POST /api/v1/cases/ returns the new case with status draft |
| Capture consent | POST /api/v1/consent/ returns the consent record with audit metadata |
| Create a doctor | POST /api/v1/doctors/ returns the new doctor profile |
400 Bad Request¶
The request was malformed or violates business rules that are not validation-specific.
| Scenario | Error Code | Example |
|---|---|---|
Missing X-Tenant-ID header |
TENANT_HEADER_MISSING_001 |
Request sent without the required tenant header |
| Modifying a closed case | INTAKE_CASE_CLOSED_001 |
PATCH /api/v1/cases/case-closed-456 on a finalized case |
| Input blocked by guardrail | AGENT_GUARDRAIL_INPUT_001 |
Chat message contained prohibited content |
| Exceeding video participant limit | VIDEO_PARTICIPANT_LIMIT_001 |
Joining a session that is already at capacity |
| Context window overflow | AGENT_CONTEXT_OVERFLOW_001 |
Chat history too long for the LLM context window |
401 Unauthorized¶
Authentication is missing or invalid. The client must provide valid credentials.
| Scenario | Error Code | Example |
|---|---|---|
| No Authorization header | AUTH_HEADER_MISSING_001 |
Request sent without a Bearer token |
| Expired JWT | AUTH_TOKEN_EXPIRED_001 |
Token TTL exceeded; user needs to re-authenticate via Clerk |
| Invalid JWT signature | AUTH_TOKEN_INVALID_001 |
Token was tampered with or issued by an untrusted provider |
403 Forbidden¶
The client is authenticated but does not have permission for the requested action.
| Scenario | Error Code | Example |
|---|---|---|
| Insufficient role permissions | AUTH_UNAUTHORIZED_001 |
A viewer role attempting to delete a case |
| Tenant ID mismatch | TENANT_MISMATCH_001 |
JWT tenant claim does not match X-Tenant-ID header |
| Missing patient consent | CONSENT_REQUIRED_001 |
Attempting to share patient data without active consent |
404 Not Found¶
The requested resource does not exist or the client does not have visibility into it.
| Scenario | Error Code | Example |
|---|---|---|
| Case not found | INTAKE_CASE_NOT_FOUND_001 |
GET /api/v1/cases/nonexistent-id |
| Tenant not found | TENANT_NOT_FOUND_001 |
X-Tenant-ID references a non-existent tenant |
| Provider not found | PROVIDER_NOT_FOUND_001 |
GET /api/v1/providers/invalid-id |
| Doctor not found | DOCTOR_NOT_FOUND_001 |
GET /api/v1/doctors/invalid-id |
| No matching providers | MATCH_NO_RESULTS_001 |
Semantic search returned zero results |
| FHIR resource not found | FHIR_RESOURCE_NOT_FOUND_001 |
GET /api/v1/fhir/Patient/nonexistent |
| Consent not found | CONSENT_NOT_FOUND_001 |
No consent record for the given patient/purpose |
| Email template not found | NOTIFY_TEMPLATE_NOT_FOUND_001 |
Referenced template ID does not exist |
| Video session not found | VIDEO_SESSION_NOT_FOUND_001 |
GET /api/v1/video/sessions/invalid-id |
409 Conflict¶
The request conflicts with the current state of a resource.
| Scenario | Error Code | Example |
|---|---|---|
| Duplicate patient | INTAKE_DUPLICATE_001 |
Creating a patient with an email + DOB that already exists |
| Provider at capacity | PROVIDER_CAPACITY_001 |
Assigning a case to a provider that has reached their limit |
| Duplicate doctor | DOCTOR_DUPLICATE_001 |
Creating a doctor with an existing license number |
| Duplicate procedure link | DOCTOR_PROCEDURE_EXISTS_001 |
Associating a doctor with a procedure they already perform |
| Consent already revoked | CONSENT_ALREADY_REVOKED_001 |
Revoking consent that was already revoked |
413 Payload Too Large¶
The uploaded file exceeds the maximum allowed size.
| Scenario | Error Code | Example |
|---|---|---|
| File too large | STORAGE_FILE_TOO_LARGE_001 |
Uploading a file that exceeds the 20 MB limit |
422 Unprocessable Entity¶
The request body is syntactically valid JSON but fails semantic validation.
| Scenario | Error Code | Example |
|---|---|---|
| Field validation failure | INTAKE_VALIDATION_001 |
Missing first_name, invalid email format |
| FHIR schema violation | FHIR_RESOURCE_INVALID_001 |
Patient resource missing required name field |
| Unknown coding system | FHIR_CODING_UNKNOWN_001 |
Invalid ICD-10 code in a Condition resource |
| Doctor validation failure | DOCTOR_VALIDATION_001 |
Missing specialty or license number |
| Invalid file type | STORAGE_FILE_TYPE_001 |
Uploading an unsupported file format (e.g., .exe) |
| Invalid notification recipient | NOTIFY_RECIPIENT_INVALID_001 |
Malformed email address in notification request |
429 Too Many Requests¶
Rate limit exceeded. The response includes Retry-After and X-RateLimit-Reset headers.
| Scenario | Error Code | Example |
|---|---|---|
| Tenant rate limit | SYS_RATE_LIMITED_001 |
Exceeding 60 req/min on the free tier |
| Notification rate limit | NOTIFY_RATE_LIMITED_001 |
Sending too many emails in a short window |
500 Internal Server Error¶
An unexpected error occurred on the server. These should be reported as bugs if they persist.
| Scenario | Error Code | Example |
|---|---|---|
| Unhandled exception | SYS_INTERNAL_001 |
Uncaught error in application code |
| Embedding generation failed | MATCH_EMBEDDING_FAILED_001 |
OpenAI/Qdrant embedding service returned an error |
| Graph query failed | MATCH_GRAPH_QUERY_FAILED_001 |
Neo4j Cypher query execution error |
| Guardrail output blocked | AGENT_GUARDRAIL_OUTPUT_001 |
LLM response failed the output validator |
| File upload failed | STORAGE_UPLOAD_FAILED_001 |
Cloudflare R2 write operation failed |
| Presigned URL failed | STORAGE_PRESIGN_FAILED_001 |
R2 credential issue during URL signing |
| Email send failed | NOTIFY_EMAIL_FAILED_001 |
Resend API returned an error |
| Graph query execution error | GRAPH_QUERY_FAILED_001 |
Malformed Cypher or constraint violation |
502 Bad Gateway¶
An upstream service returned an invalid response.
| Scenario | Error Code | Example |
|---|---|---|
| Video provider error | VIDEO_PROVIDER_ERROR_001 |
Third-party video service returned a malformed response |
503 Service Unavailable¶
A required downstream service is unavailable.
| Scenario | Error Code | Example |
|---|---|---|
| Database unreachable | SYS_DATABASE_001 |
PostgreSQL connection pool exhausted or host unreachable |
| Neo4j unreachable | GRAPH_CONNECTION_001 |
Neo4j instance is down or NEO4J_URI is misconfigured |
| Scheduled maintenance | SYS_MAINTENANCE_001 |
System is in a maintenance window |
504 Gateway Timeout¶
The server did not receive a timely response from an upstream service.
| Scenario | Error Code | Example |
|---|---|---|
| LLM timeout | AGENT_LLM_TIMEOUT_001 |
LLM provider did not respond within the configured timeout |
| General timeout | SYS_TIMEOUT_001 |
Complex query or downstream service exceeded the deadline |
410 Gone¶
The resource existed but is no longer available.
| Scenario | Error Code | Example |
|---|---|---|
| Video session expired | VIDEO_SESSION_EXPIRED_001 |
The video session TTL has elapsed |
Response Headers¶
All error responses include these headers when applicable:
| Header | Present On | Description |
|---|---|---|
Retry-After |
429, 503 | Seconds to wait before retrying |
X-RateLimit-Limit |
All | Maximum requests per window |
X-RateLimit-Remaining |
All | Requests remaining in the current window |
X-RateLimit-Reset |
All | Unix timestamp when the window resets |
X-Request-ID |
All | Unique request identifier for log correlation |