Response envelope
Every successful /api/v1/* response uses the same envelope shape.
This page documents the envelope, the error variant, the conventions
for cache control and warnings, and how to read partial results.
The locked decision is ADR 0012; the full grammar is in the Backend API spec.
Success envelope
{ "data": { ... }, "meta": { "api_version": "v1", "catalog_version_id": "math-2026-spring", "request_id": "req_01H...", "evaluated_at": "2026-05-15T21:33:00Z" }, "warnings": [ { "code": "graph_view_truncated", "message": "..." } ], "unknowns": [ { "target": "course:MATH 999", "unknown_reason": "unparsed_requirement", "source_reference_id": "sref_..." } ], "source_references": [ { "source_reference_id": "sref_...", "kind": "course_prerequisite_text", "...": "..." } ]}Field-by-field:
| Field | Required | Purpose |
|---|---|---|
data | success-only | The primary payload for this endpoint. |
meta | always | API version, catalog version pinned to this response, request id, evaluation timestamp. |
warnings | always | Non-fatal advisories (truncation, partial data, deprecation). |
unknowns | always | Things the engine could not resolve, with reason codes. Distinct from warnings. |
source_references | always | Full record for every referenced source-reference id in this response. |
The arrays may be empty but they are always present, so client code can iterate without null checks.
Error envelope
{ "error": { "code": "bad_request", "message": "...", "details": { ... } }, "meta": { "api_version": "v1", "request_id": "req_01H..." }}Error responses never carry data. HTTP status follows RFC 9110
semantics. The error code is a machine-readable token; see
Errors.
HTTP semantics
- Method semantics follow RFC 9110.
GETis safe and idempotent;POSTis non-idempotent (state-creating or query-evaluating);PATCHis non-idempotent state mutation;PUTis idempotent replacement;DELETEis idempotent removal. - Caching follows RFC 9111. State-bearing responses
(
/api/v1/state/current/*) includeCache-Control: no-store. Read-only catalog responses may carry validation freshness signals.
Truncation
Bounded-by-design endpoints (graph views, Advisory enumeration) may return less than the conceptual answer. Truncation is not an error:
- Status remains
200 OK. - The response includes a
graph_view_truncated(or similar) entry inwarnings. - A reciprocal
omittedcount appears inmetaso the client can display “showing N of M”.
Bounded-breach (request exceeds hard maxima) returns 400 bad_request,
because the client asked for something the server has been configured
to refuse. See ADR 0009 §“hard maxima”
and the graph-view response spec.
Warnings vs unknowns
- Warnings describe a property of the response (truncated, deprecated, slow). They are advice to the caller, not facts about academic content.
- Unknowns describe a property of the academic content (this
sub-requirement is unresolved). They survive end-to-end so the
frontend can render
unknownstatuses with click-through reason codes.
Catalog version pinning
Every response includes meta.catalog_version_id. If a client passes a
state pinned to a different catalog version, the mismatch is reported
explicitly in the envelope rather than silently coerced.
Want the full spec?
- Backend API spec — every endpoint, every payload.
- ADR 0012 — locked envelope contract.