Response Envelope
Every successful platform-api response is wrapped by a global TransformInterceptor. Your actual payload is in data.
{
"code": 200,
"data": { "id": "clx...", "title": "Frontend Resume" },
"message": "success",
"timestamp": "2026-06-19T08:00:00.000Z"
}| Field | Type | Meaning |
|---|---|---|
code | number | Application status (mirrors HTTP status on success) |
data | any | Your real payload — object, array, or primitive |
message | string | Human-readable status ("success" on the happy path) |
timestamp | ISO string | When the response was produced |
Return values from controllers are the raw data; the interceptor adds the envelope. So when this documentation says an endpoint “returns the created resume,” that resume is at response.data.
Unwrapping in code
Centralize the unwrap so call sites stay clean:
type Envelope<T> = { code: number; data: T; message: string; timestamp: string }
async function call<T>(url: string, init?: RequestInit): Promise<T> {
const res = await fetch(url, init)
const body = (await res.json()) as Envelope<T>
if (!res.ok || body.code >= 400) {
throw new Error(body.message || `HTTP ${res.status}`)
}
return body.data
}What is not enveloped
A few responses bypass the envelope by design:
| Endpoint | Why |
|---|---|
All text/event-stream endpoints (agent-service) | Stream raw data: SSE frames, not a single JSON body |
| Errors | Shaped by the HttpExceptionFilter — see Errors |
The envelope is a platform-api convention. Agent-service streaming endpoints emit their own SSE event objects ({ type, runId, ... }) and are never wrapped — see SSE events.
Last updated on