Standard Response Envelope¶
Every API response from Curaway follows a consistent envelope structure. This makes it predictable for frontend consumers and simplifies error handling across all endpoint groups.
Envelope Schema¶
{
"success": true,
"data": { ... },
"errors": null,
"meta": null,
"api_version": "v1",
"timestamp": "2026-03-31T12:00:00.000Z"
}
Field Definitions¶
| Field | Type | Description |
|---|---|---|
success |
boolean |
true if the request completed without errors, false otherwise |
data |
object \| array \| null |
The response payload. null when success is false |
errors |
array \| null |
List of error objects. null when success is true |
meta |
object \| null |
Optional metadata such as pagination cursors, total counts, or request IDs |
api_version |
string |
Always "v1" for the current API version |
timestamp |
string |
ISO 8601 timestamp of when the response was generated (UTC) |
Success Response¶
When a request succeeds, success is true, data contains the result, and errors is null.
Example: Retrieve a Case¶
Request:
Response (200 OK):
{
"success": true,
"data": {
"id": "case-abc-123",
"patient_id": "pat-001",
"status": "in_review",
"procedure": "Hip Replacement",
"destination_country": "DE",
"created_at": "2026-03-15T10:30:00.000Z",
"updated_at": "2026-03-28T14:22:00.000Z",
"assigned_provider_id": "prov-berlin-ortho-01",
"document_checklist": {
"total": 5,
"completed": 3,
"pending": ["medical_report", "insurance_letter"]
}
},
"errors": null,
"meta": {
"request_id": "req-7f3a2b1c"
},
"api_version": "v1",
"timestamp": "2026-03-31T12:00:00.000Z"
}
Example: List Providers with Pagination¶
Request:
Response (200 OK):
{
"success": true,
"data": [
{
"id": "prov-berlin-ortho-01",
"name": "Berlin Orthopedic Center",
"country": "DE",
"specialties": ["orthopedics", "sports_medicine"],
"accreditations": ["JCI", "ISO_9001"]
},
{
"id": "prov-munich-cardio-01",
"name": "Munich Heart Clinic",
"country": "DE",
"specialties": ["cardiology", "cardiac_surgery"],
"accreditations": ["JCI"]
}
],
"errors": null,
"meta": {
"page": 1,
"page_size": 2,
"total_count": 12,
"total_pages": 6,
"request_id": "req-9e4c5d2a"
},
"api_version": "v1",
"timestamp": "2026-03-31T12:01:00.000Z"
}
Example: Create a Patient (201 Created)¶
Request:
POST /api/v1/patients/
X-Tenant-ID: tenant-apollo-001
Content-Type: application/json
{
"first_name": "Aisha",
"last_name": "Patel",
"date_of_birth": "1985-06-15",
"email": "aisha.patel@example.com",
"phone": "+971501234567",
"country_of_residence": "AE"
}
Response (201 Created):
{
"success": true,
"data": {
"id": "pat-a1b2c3d4",
"first_name": "Aisha",
"last_name": "Patel",
"date_of_birth": "1985-06-15",
"email": "aisha.patel@example.com",
"phone": "+971501234567",
"country_of_residence": "AE",
"created_at": "2026-03-31T12:05:00.000Z"
},
"errors": null,
"meta": null,
"api_version": "v1",
"timestamp": "2026-03-31T12:05:00.000Z"
}
Error Response¶
When a request fails, success is false, data is null, and errors contains one or more error objects.
Error Object Schema¶
Each error in the errors array follows this structure:
| Field | Type | Description |
|---|---|---|
code |
string |
Machine-readable error code (e.g., AUTH_TOKEN_EXPIRED_001) |
message |
string |
Human-readable error description |
field |
string \| null |
The request field that caused the error, if applicable |
Example: Validation Error (422)¶
Request:
POST /api/v1/patients/
X-Tenant-ID: tenant-apollo-001
Content-Type: application/json
{
"first_name": "",
"email": "not-an-email"
}
Response (422 Unprocessable Entity):
{
"success": false,
"data": null,
"errors": [
{
"code": "INTAKE_VALIDATION_001",
"message": "first_name must not be empty",
"field": "first_name"
},
{
"code": "INTAKE_VALIDATION_001",
"message": "Invalid email format",
"field": "email"
},
{
"code": "INTAKE_VALIDATION_001",
"message": "last_name is required",
"field": "last_name"
}
],
"meta": null,
"api_version": "v1",
"timestamp": "2026-03-31T12:10:00.000Z"
}
Example: Authentication Error (401)¶
Response (401 Unauthorized):
{
"success": false,
"data": null,
"errors": [
{
"code": "AUTH_TOKEN_EXPIRED_001",
"message": "JWT token has expired. Please re-authenticate.",
"field": null
}
],
"meta": null,
"api_version": "v1",
"timestamp": "2026-03-31T12:15:00.000Z"
}
Frontend Usage Pattern¶
The consistent envelope allows a single response handler in the frontend:
async function apiCall<T>(url: string, options?: RequestInit): Promise<T> {
const response = await fetch(url, {
...options,
headers: {
'X-Tenant-ID': getTenantId(),
'Authorization': `Bearer ${getToken()}`,
'Content-Type': 'application/json',
...options?.headers,
},
});
const envelope = await response.json();
if (!envelope.success) {
throw new ApiError(envelope.errors, response.status);
}
return envelope.data as T;
}
Notes¶
- The
timestampfield is always in UTC and uses ISO 8601 format. - The
metafield is only populated when there is relevant metadata (pagination, request tracing, etc.). - Multiple validation errors can be returned in a single response -- the
errorsarray may contain more than one entry. - The
fieldproperty in error objects isnullfor errors not tied to a specific input field (e.g., authentication failures, rate limiting).