JSON success responses return this envelope:
List endpoints keep named collections in data and place pagination metadata in top-level meta:
Errors return this envelope:
error.code is stable and machine-readable. Clients should branch on the code instead of parsing message. Domain failures use specific codes such as invalid_period, invoice_already_generated, payment_already_reversed, organization_suspended, and room_has_active_lease. error.message is localized to the request Accept-Language (vi default, en) and the chosen locale is echoed in the Content-Language response header. error.code and fields[].code / fields[].path stay identical across locales — see Errors. /api/v1/openapi.json returns the raw OpenAPI document for tooling. CSV exports return text/csv.