Core concepts
Responses & errors
The single response envelope every endpoint returns, pagination, and the full error-code catalogue.
Every endpoint — success or failure — returns the same JSON envelope.
The envelope
{
"data": { "...": "the payload (or null)" },
"meta": {
"success": true,
"message": "optional human-readable message",
"errorCode": null,
"timestamp": "2026-06-04T10:00:00Z"
},
"pagination": null
}| Field | Meaning |
|---|---|
data | The payload on success. For list endpoints, this is the page's items. |
meta.success | Boolean outcome flag. |
meta.message | Optional narrative (e.g. "Resource created" or an error description). |
meta.errorCode | Stable machine-readable code on failure (see below); null on success. |
meta.timestamp | Server UTC instant. |
pagination | Present only on list endpoints. |
Branch on meta.errorCode, not on meta.message — messages are for humans and may
change; codes are part of the contract and never change meaning.
Pagination
List endpoints put the items in data and the page info in pagination:
{
"data": ["...items..."],
"meta": { "success": true, "timestamp": "2026-06-04T10:00:00Z" },
"pagination": { "page": 0, "size": 20, "totalElements": 137, "totalPages": 7 }
}Pages are zero-indexed. Pass page and size as query parameters; most list
endpoints also accept sortBy and order (ASC/DESC).
Error codes
Errors return the envelope with meta.success = false and a meta.errorCode. The
HTTP status reflects the category.
errorCode | HTTP | Meaning |
|---|---|---|
VALIDATION_ERROR | 400 | Request failed validation; data holds a field → message map. |
UNAUTHORIZED | 401 | Missing/invalid credentials. |
TOKEN_EXPIRED / SESSION_EXPIRED | 401 | Admin session no longer valid. |
REAUTH_REQUIRED | 401 | Admin must re-authenticate before a sensitive action. |
INVALID_CREDENTIALS | 401 | Bad email/password (admin login). |
FORBIDDEN | 403 | Authenticated but not permitted. |
RESOURCE_NOT_FOUND | 404 | No such resource in your scope. |
RESOURCE_ALREADY_EXISTS | 409 | Uniqueness conflict. |
INVALID_OPERATION_STATE | 409 | The resource isn't in a state that allows the action. |
IDEMPOTENCY_KEY_CONFLICT | 409 | Same idempotency key, different body. |
IDEMPOTENCY_IN_PROGRESS | 409 | Same idempotency key still processing. |
LAST_SUPER_ADMIN_PROTECTED | 409 | Cannot disable the last Super Admin. |
LEDGER_ALREADY_REVERSED | 409 | A ledger entry was asked to be reversed twice. |
ACCOUNT_LOCKED / ACCOUNT_DISABLED | 403 | Admin account not usable. |
WEAK_PASSWORD | 400 | Password does not meet policy. |
PAYMENT_GATEWAY_ERROR | 502 | The gateway was unreachable or rejected the operation. |
LEDGER_UNBALANCED | 500 | Internal invariant breach (debits ≠ credits). |
INTERNAL_ERROR | 500 | Unexpected server error. |
Validation errors
A 400 VALIDATION_ERROR puts the per-field messages in data:
{
"data": { "amountMinor": "must be greater than 0" },
"meta": { "success": false, "errorCode": "VALIDATION_ERROR",
"message": "Validation failed", "timestamp": "…" }
}