The response envelope & versioning
Why every Braize-native response is {data, meta}, how contract versioning works, and what additive-only evolution means for your integration.
Why an envelope at all
Every Braize-native endpoint (everything except the OpenAI-compatible endpoint, which has its own documented exception) returns:
{ "data": { /* the actual payload */ }, "meta": { "request_id": "…", "braize_version": "2026-09-01" } }The envelope exists so response-level metadata (a request id for support,
the contract version a response was generated against, a degraded flag)
never has to be smuggled into the payload shape itself or invented as a
one-off header per endpoint. meta grows over time without ever touching
data's shape.
meta.degraded is worth watching: it's true when a response was produced
during a provider outage (e.g. retrieval fell back to lexical-only search
because the embedding provider was briefly unavailable). That's not an
error — you still got an answer — but you may want to surface it, or retry
later for a stronger one.
Additive-only, forever
The contract only ever grows. In practice that means, permanently:
- A field is never removed or renamed.
- A field's type or meaning never changes.
- An optional field never becomes required.
- An error
typeURI is never repurposed for a different condition (see Handling errors). - New capability arrives as a new field, a new endpoint, or (for MCP) a new tool — never a breaking change to something that already shipped.
The practical implication for your integration: parse tolerantly.
Ignore fields and enum values you don't recognize instead of failing on
them; a JSON-Schema validator set to additionalProperties: false against
an exact snapshot of today's response shape will eventually break on a
perfectly normal, non-breaking addition. Several request schemas
(QueryRequest, RetrieveRequest) explicitly declare
additionalProperties: true for exactly this must-ignore contract.
Pinning a version on purpose
Every response's meta.braize_version names the contract date it was
generated against (e.g. 2026-09-01). Because the contract is
additive-only, you don't normally need to do anything — new responses stay
compatible with code written against an older version. If you want to
freeze behavior explicitly anyway (e.g. for a reproducible test suite), send
Braize-Version: 2026-09-01 as a request header; see
Pinning a contract version
in Authentication & regions.
Pagination is opaque
Where a list response paginates (GET /v1/documents), the next_cursor
field is an opaque forward token, not something to parse or construct
yourself. Pass it back verbatim as ?cursor=. Treating it as opaque is what
lets the underlying pagination implementation change without breaking
every client that stored a cursor.
What's next
- Handling errors — the other half of the contract: what a non-success response looks like and why it's typed the same way everywhere.
- Core concepts — the product principles this contract exists to enforce.