Response Envelope
Every response — success, validation failure, or server error — follows a single predictable envelope. Parse once, use everywhere.
{ "success": true, "message": "Human-readable status", "data": { /* resource, list, or null on error */ }, "errorCode": null, "meta": { "pagination": { "total": 120, "page": 1, "limit": 20, "totalPages": 6 } }}Fields
| Field | Type | Description |
|---|---|---|
success | boolean | true for 2xx responses, false otherwise. |
message | string | Short status message, suitable for logs (not end-user copy). |
data | object | array | null | Resource payload. null on error responses. |
errorCode | string | null | Stable machine-readable code (see errors). null on success. |
errors | array? | Validation failures — array of { field, message }. |
meta | object? | Optional metadata (pagination, rate-limit headers mirrored, etc.). |
Success example
{ "success": true, "message": "User profile", "data": { "id": 42, "msisdn": "8801712345678", "name": "Jane Doe" }, "errorCode": null}Error example
{ "success": false, "message": "Validation failed", "data": null, "errorCode": "VALIDATION_ERROR", "errors": [ { "field": "email", "message": "email must be a valid email" } ]}Paginated list example
{ "success": true, "message": "OK", "data": [ /* items */ ], "errorCode": null, "meta": { "pagination": { "total": 120, "page": 1, "limit": 20, "totalPages": 6 } }}Use the X-Total-Count, X-Page, and X-Limit response headers if you’d
rather not parse meta — they carry the same values.