Errors
Moyo Suite doesn’t use one uniform error envelope everywhere. Most endpoints return a plain message; a handful of endpoints — permissions, plan/module gating, and a few business-rule checks — return a richer structured object. Both are real, and you should handle both.
The common case: a plain message
The structured case: permission and entitlement errors
Requests blocked by RBAC or by your organization’s plan return a code you
can branch on, plus a human-readable message:
A few other endpoints — expense approval/rejection, data import mapping —
use the same {code, message} shape for their own business-rule errors
(e.g. read_only_field, approved_expense_cannot_be_edited).
Validation errors (422)
Request-body validation failures always come back the same way, with one
entry per invalid field plus a request_id:
Status codes
Every response carries a request ID — in the header
Every response — success or failure — includes an X-Request-ID header.
Include it when reporting an issue.
The response body only echoes request_id for two cases: 422
validation errors (shown above) and unhandled 500s. A plain
{"detail": "..."} error (404s, most 400s, RBAC/entitlement 403s, etc.)
does not include request_id in its body — read it from the header
instead.