---
title: "List a session's telemetry frames"
method: GET
path: "/phones/sessions/{session_id}/frames"
tags: ["runs"]
---

# List a session's telemetry frames

`GET /phones/sessions/{session_id}/frames`

Returns the paginated telemetry frames for a session in the canonical frame envelope: one completed span frame per durable span (operations that never completed appear via their synthesized failed closures) plus log frames, ordered by span start / log time, with response-level billed-cost maps. This is the same envelope the live telemetry WebSocket streams; live and archive differ only in cardinality (start+end frames live, one completed frame here). Org-scoped: another org's session reads as not found. A trace past the organization's telemetry retention window returns an empty list with retention_expired=true; when the retention policy itself cannot be resolved the request fails with a 500 rather than serving frames whose retention state is unknown. Tolerant reader (unified frame contract): consumers MUST ignore frames with an unknown kind, unknown fields within known kinds, and unknown span_type/log_type values (render generically, never error). Generated SDK types surface an unrecognized frame as an explicit UnknownFrame variant carrying the raw JSON, never a silent drop. A live-stream message MAY carry a JSON array of frame objects; consumers MUST accept a single object or an array.

## Path parameters

- `session_id` string, required — Session whose frames to return.

## Query parameters

- `limit` integer — Maximum number of frames to return (1-1000).
- `offset` integer — Pagination offset.

## Response `200`

OK

- RunSessionFramesResponse — Paginated list of telemetry frames for a session.
  - `$schema` string, uri — A URL to the JSON Schema for this object.
  - `frames` union[], nullable, required — Page of frames, ordered by span start / log time.
    - union — One telemetry frame: a completed span or a log event, discriminated on kind. Tolerant reader (unified frame contract): consumers MUST ignore frames with an unknown kind, unknown fields within known kinds, and unknown span_type/log_type values (render generically, never error). Generated SDK types surface an unrecognized frame as an explicit UnknownFrame variant carrying the raw JSON, never a silent drop. A live-stream message MAY carry a JSON array of frame objects; consumers MUST accept a single object or an array.
      - RunSpanFrame — One completed telemetry span in the canonical frame envelope.
        - `attributes` object — Every attribute the producer stamped (axilio.* vocabulary), verbatim. Attributes are the contract's extension seam: new keys appear here without a version bump.
        - `end_time_unix_nano` integer, required — Span end, nanoseconds since the Unix epoch.
        - `kind` 'span', required — Frame kind discriminator; always "span" for span frames.
        - `name` string, required — Span name (for sdk_call spans, the SDK operation, e.g. Screen.observe).
        - `parent_span_id` string — Parent span id; omitted on root spans.
        - `phase` string, required — Span phase. The archive returns completed spans only ("end"); "start" phases exist only on the live stream.
        - `span_id` string, required — OTel span id (16 lowercase hex chars). Upsert key: the live copy of this span carries the same id.
        - `span_type` string, required — Product span role: session (the session root), run, sdk_call, inference, file_push, media_capture. Spans stored before the 2026-08-21 vocabulary cutover carry the retired phone_session value for the session root. Unknown values MUST be rendered generically, never rejected.
        - `start_time_unix_nano` integer, required — Span start, nanoseconds since the Unix epoch.
        - `status` RunFrameStatus, required — Span outcome.
          - `code` string, required — "ok" or "error".
          - `message` string, required — Human-readable failure message; empty on success.
        - `trace_id` string, required — OTel trace id (32 lowercase hex chars), derived from the session id: one session is one trace.
      - RunLogFrame — One point-in-time telemetry log event in the canonical frame envelope.
        - `attributes` object — Every attribute the producer stamped (axilio.* vocabulary), verbatim.
        - `body` string, required — The log's human-readable text.
        - `kind` 'log', required — Frame kind discriminator; always "log" for log frames.
        - `log_type` string, required — Product log type, e.g. output_log, output_error, kernel_status, transfer_progress. Unknown values MUST be rendered generically, never rejected.
        - `severity` string, required — Log severity (INFO / ERROR).
        - `span_id` string — Span the log occurred under; omitted for session-level logs.
        - `time_unix_nano` integer, required — Event time, nanoseconds since the Unix epoch.
        - `trace_id` string, required — OTel trace id (32 lowercase hex chars) of the session the log belongs to.
  - `inference_costs` object, required — Billed microdollars per inference_id, the per-inference detail behind sdk_call_costs.
  - `limit` integer, required — Page size used for this response.
  - `offset` integer, required — Pagination offset used for this response.
  - `retention_expired` boolean, required — True when the trace is past the org's retention window; frames are withheld and the underlying data is deleted by a daily sweep.
  - `sdk_call_costs` object, required — Billed microdollars per sdk_call span_id (post-markup, what the invoice charges). Response-level by design: billed cost is a read-time billing join, never a frame attribute.
  - `total` integer, required — Total number of frames for the session.

## Other responses

- `default` — Error

---

[API](https://skmtc.net/axilioai/apis/axilio-api.md) · [All operations](https://skmtc.net/axilioai/apis/axilio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/axilioai/axilio-api/revisions/c0bcdbdbb247/schema)
