---
title: "Get Session Records"
method: GET
path: "/v1/sessions/{id}/records"
tags: ["v1"]
---

# Get Session Records

`GET /v1/sessions/{id}/records`

## Request

- Base URL: `https://api.ellipsis.dev`
- URL: `https://api.ellipsis.dev/v1/sessions/{id}/records`
- Auth: HTTP bearer

Return the session's stored transcript records, oldest first.

Pagination is opt-in (cursor/limit); a bare call returns the
full retained transcript. Available to session tokens too: an
agent answering "did X look into Y?" needs to read the sessions
it finds, and any org member sees the same transcript in the
dashboard.

## Path parameters

- `id` string, required

## Query parameters

- `cursor` string, nullable
- `limit` integer, nullable
- `message_id` string, nullable: Keep only the records of this message.

## Headers

- `user-agent` string, nullable

## Response `200`

Successful Response

- SessionRecordsListResponse: A session's log: everything that happened, oldest first.
  - `earliest_feed_seq` integer, nullable: The retention head: the lowest feed_seq still stored, or null when the session has no stored records.
  - `has_more` boolean: Whether more results exist past this page.
  - `next_cursor` string, nullable: Pass as `cursor` to fetch the next page. Null on the last page. Opaque — echo it back rather than parsing it.
  - `records` SessionRecord[], required: The session's records, ordered by feed_seq: the messages sent to it, the platform's own events, and the agent's output. Clients render each by (source, record_format, record_type). Pagination is opt-in (`cursor` + `limit`); a bare call returns the full retained log.
    - union
      - ClaudeSessionRecord: Historical Claude SDK projection, retained for existing session history.
        - `cost` integer, nullable, required
        - `created_at` string, date-time, required
        - `duration` integer, nullable, required
        - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
        - `id` string, required: Unique identifier of the record.
        - `kind` 'claude_sdk', required
        - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
        - `model` string, nullable, required
        - `payload` union, required
          - LegacyAssistantPayload
            - `cache_creation` SdkCacheCreation: The cache-write breakdown by TTL. Load-bearing for billing, not informational: the 5m and 1h lanes have different rate-card prices (`normalized_usage_from_anthropic`), so collapsing them into one `cache_creation_input_tokens` total silently misprices every session with 1h caching on.
              - …
            - `content` union[]
              - …
            - `error` string, nullable
            - `kind` 'assistant', required
            - `message_id` string, nullable
            - `model` string, required
            - `parent_tool_use_id` string, nullable
            - `session_id` string, nullable
            - `stop_reason` string, nullable
            - `usage` LegacyNativeUsage: Native usage extensions remain data, independent of strict accounting.
              - …
            - `uuid` string, nullable
          - SdkUserRecord
            - `content` union, required
              - …
            - `kind` 'user', required
            - `parent_tool_use_id` string, nullable
            - `uuid` string, nullable
          - SdkSystemRecord: Everything the CLI reports out-of-band: init, compact_boundary, task lifecycle, hook events, api_error. `data` is the raw payload — this is the one open shape in the schema, because the CLI's system subtypes are an open set we do not want to fail a session over.
            - `data` object
            - `kind` 'system', required
            - `session_id` string, nullable
            - `subtype` string, required
            - `uuid` string, nullable
          - LegacyResultPayload
            - `api_error_status` integer, nullable
            - `cost_usd` number, nullable
            - `duration_api_ms` integer, required
            - `duration_ms` integer, required
            - `errors` string[], nullable
            - `is_error` boolean, required
            - `kind` 'result', required
            - `model_usage` object, nullable
            - `num_turns` integer, required
            - `result` string, nullable
            - `session_id` string, nullable
            - `stop_reason` string, nullable
            - `structured_output` unknown
            - `subtype` string, required
            - `usage` LegacyNativeUsage: Native usage extensions remain data, independent of strict accounting.
              - …
            - `uuid` string, nullable
          - SdkRateLimitRecord
            - `kind` 'rate_limit', required
            - `rate_limit_type` string, nullable
            - `resets_at` integer, nullable
            - `session_id` string, nullable
            - `status` string, required
            - `utilization` number, nullable
            - `uuid` string, nullable
        - `record_format` 'claude_sdk@1', required
        - `record_type` string, required: Original record type within its format.
        - `session_id` string, required: Session containing this record.
        - `source` 'claude_code', required
        - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
          - `cache_creation_input_tokens` integer
          - `cache_read_input_tokens` integer
          - `cost_usd` number
          - `input_tokens` integer
          - `num_turns` integer
          - `output_tokens` integer
        - `tools` string[], nullable, required
      - ClaudeNativeSessionRecord: Complete native Claude Code message, before SDK projection.
        - `cost` integer, nullable, required
        - `created_at` string, date-time, required
        - `duration` integer, nullable, required
        - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
        - `id` string, required: Unique identifier of the record.
        - `kind` 'claude_code', required
        - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
        - `model` string, nullable, required
        - `payload` union, required
          - ClaudeAssistantEvent
            - `error` string, nullable
            - `message` ClaudeAssistantMessage, required
              - …
            - `parent_tool_use_id` string, nullable
            - `session_id` string, nullable
            - `type` 'assistant', required
            - `uuid` string, nullable
          - ClaudeUserEvent
            - `isReplay` boolean, nullable
            - `message` ClaudeUserMessage, required
              - …
            - `parent_tool_use_id` string, nullable
            - `session_id` string, nullable
            - `type` 'user', required
            - `uuid` string, nullable
          - ClaudeSystemEvent
            - `session_id` string, nullable
            - `subtype` string, required
            - `type` 'system', required
            - `uuid` string, nullable
          - ClaudeResultEvent
            - `duration_api_ms` integer, required
            - `duration_ms` integer, required
            - `errors` string[], nullable
            - `is_error` boolean, required
            - `modelUsage` object, nullable
            - `num_turns` integer, required
            - `result` string, nullable
            - `session_id` string, nullable
            - `stop_reason` string, nullable
            - `structured_output` unknown
            - `subtype` string, required
            - `total_cost_usd` number, nullable
            - `type` 'result', required
            - `usage` ClaudeNativeUsage
              - …
            - `uuid` string, nullable
          - ClaudeRateLimitEvent
            - `rate_limit_info` ClaudeRateLimitInfo, required
              - …
            - `session_id` string, nullable
            - `type` 'rate_limit_event', required
            - `uuid` string, nullable
          - ClaudeConversationResetEvent
            - `new_conversation_id` string, required
            - `session_id` string, nullable
            - `type` 'conversation_reset', required
            - `uuid` string, nullable
        - `record_format` 'claude_jsonl@1', required
        - `record_type` string, required: Original record type within its format.
        - `session_id` string, required: Session containing this record.
        - `source` 'claude_code', required
        - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
          - `cache_creation_input_tokens` integer
          - `cache_read_input_tokens` integer
          - `cost_usd` number
          - `input_tokens` integer
          - `num_turns` integer
          - `output_tokens` integer
        - `tools` string[], nullable, required
      - CodexSessionRecord
        - `cost` integer, nullable, required
        - `created_at` string, date-time, required
        - `duration` integer, nullable, required
        - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
        - `id` string, required: Unique identifier of the record.
        - `kind` 'codex', required
        - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
        - `model` string, nullable, required
        - `payload` union, required
          - CodexThreadStartedEvent
            - `thread_id` string, nullable
            - `type` 'thread.started', required
          - CodexTurnStartedEvent
            - `type` 'turn.started', required
          - CodexTurnCompletedEvent
            - `type` 'turn.completed', required
            - `usage` CodexUsage: The `usage` object on a `turn.completed` event — one turn's token counts. Note the field names differ from BOTH the Responses API and chat completions: Codex reports `cached_input_tokens` / `cache_write_input_tokens` where the Responses API says `input_tokens_details.cached_tokens`. These counts are for display/records only — billing cost comes from the proxy's own ledger, which prices the provider's usage, so a drift here can never mis-bill.
              - …
          - CodexTurnFailedEvent
            - `error` object, nullable
            - `type` 'turn.failed', required
          - CodexErrorEvent
            - `message` string, nullable
            - `type` 'error', required
          - CodexItemStartedEvent
            - `item` union, required
              - …
            - `type` 'item.started', required
          - CodexItemUpdatedEvent
            - `item` union, required
              - …
            - `type` 'item.updated', required
          - CodexItemCompletedEvent
            - `item` union, required
              - …
            - `type` 'item.completed', required
        - `record_format` 'codex_jsonl@1', required
        - `record_type` string, required: Original record type within its format.
        - `session_id` string, required: Session containing this record.
        - `source` 'codex', required
        - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
          - `cache_creation_input_tokens` integer
          - `cache_read_input_tokens` integer
          - `cost_usd` number
          - `input_tokens` integer
          - `num_turns` integer
          - `output_tokens` integer
        - `tools` string[], nullable, required
      - CodexAppServerSessionRecord
        - `cost` integer, nullable, required
        - `created_at` string, date-time, required
        - `duration` integer, nullable, required
        - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
        - `id` string, required: Unique identifier of the record.
        - `kind` 'codex_app_server', required
        - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
        - `model` string, nullable, required
        - `payload` union, required
          - CodexThreadStarted
            - `method` 'thread/started', required
            - `params` CodexThreadStartedParams, required
              - …
          - CodexTurnStarted
            - `method` 'turn/started', required
            - `params` CodexTurnParams, required
              - …
          - CodexTurnCompleted
            - `method` 'turn/completed', required
            - `params` CodexTurnParams, required
              - …
          - CodexItemStarted
            - `method` 'item/started', required
            - `params` CodexItemParams, required
              - …
          - CodexItemCompleted
            - `method` 'item/completed', required
            - `params` CodexItemParams, required
              - …
          - CodexTokenUsageUpdated
            - `method` 'thread/tokenUsage/updated', required
            - `params` CodexTokenUsageParams, required
              - …
          - CodexAppServerError
            - `method` 'error', required
            - `params` CodexErrorParams, required
              - …
        - `record_format` 'codex_app_server@1', required
        - `record_type` string, required: Original record type within its format.
        - `session_id` string, required: Session containing this record.
        - `source` 'codex', required
        - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
          - `cache_creation_input_tokens` integer
          - `cache_read_input_tokens` integer
          - `cost_usd` number
          - `input_tokens` integer
          - `num_turns` integer
          - `output_tokens` integer
        - `tools` string[], nullable, required
      - GeminiSessionRecord
        - `cost` integer, nullable, required
        - `created_at` string, date-time, required
        - `duration` integer, nullable, required
        - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
        - `id` string, required: Unique identifier of the record.
        - `kind` 'gemini', required
        - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
        - `model` string, nullable, required
        - `payload` union, required
          - GeminiInitEvent
            - `model` string, required
            - `session_id` string, required
            - `timestamp` string, required
            - `type` 'init', required
          - GeminiMessageEvent
            - `content` string, required
            - `delta` boolean, nullable
            - `role` 'user' | 'assistant', required
            - `timestamp` string, required
            - `type` 'message', required
          - GeminiToolUseEvent
            - `parameters` object
            - `timestamp` string, required
            - `tool_id` string, required
            - `tool_name` string, required
            - `type` 'tool_use', required
          - GeminiToolResultEvent
            - `error` GeminiToolError
              - …
            - `output` string, nullable
            - `status` 'success' | 'error', required
            - `timestamp` string, required
            - `tool_id` string, required
            - `type` 'tool_result', required
          - GeminiErrorEvent
            - `message` string, required
            - `severity` string, nullable
            - `timestamp` string, required
            - `type` 'error', required
          - GeminiResultEvent
            - `error` GeminiToolError
              - …
            - `stats` GeminiStreamStats
              - …
            - `status` 'success' | 'error', required
            - `timestamp` string, required
            - `type` 'result', required
        - `record_format` 'gemini_stream_json@1', required
        - `record_type` string, required: Original record type within its format.
        - `session_id` string, required: Session containing this record.
        - `source` 'gemini', required
        - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
          - `cache_creation_input_tokens` integer
          - `cache_read_input_tokens` integer
          - `cost_usd` number
          - `input_tokens` integer
          - `num_turns` integer
          - `output_tokens` integer
        - `tools` string[], nullable, required
      - union
        - SessionClosedRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` SessionClosedPayload, required: session_closed: the session closed permanently.
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'session_closed', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - MessageRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` SessionMessage, required: One message sent to a session.
            - `author` string, nullable: Display attribution of the message's sender.
            - `body` string, required: The message text, with one `[Image #N]` placeholder per attached image.
            - `created_at` string, date-time, required: When the message was received.
            - `id` string, required: Unique identifier of the message.
            - `images` SessionMessageImage[]: Images attached to the message, metadata only: index, media type, size. The bytes go to the model, never over the stream.
              - …
            - `index` integer, required: Position in the session, starting at 0.
            - `session_id` string, required: Identifier of the session the message belongs to.
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'message', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - MessageQueuedRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` MessageQueuedPayload, required: message_queued: the message waits because the account already has `sessions_alive` sessions alive, its limit.
            - `limit` integer, required
            - `message_id` string, required
            - `sessions_alive` integer, required
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'message_queued', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - MessageStartedRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` MessageStartedPayload, required: message_started: the agent started on the message.
            - `message_id` string, required
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'message_started', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - MessageEndedRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` MessageEndedPayload, required: message_ended: the message was answered, or its answer failed, was stopped, or was cancelled. `error` is the same object as the session's `error`, null when the message was answered. `cost` and `tokens` are what answering it spent. Messages answered together report the spend once, on the last of them.
            - `cost` Cost: What something cost, in millicents.
              - …
            - `duration_ms` integer, nullable
            - `error` SessionError: Why the last message failed, was stopped, or was cancelled. Cleared when the next message starts.
              - …
            - `message_id` string, required
            - `status` string, required
            - `tokens` Tokens: Tokens used, in total and by model.
              - …
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'message_ended', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - MessageRequeuedRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` MessageRequeuedPayload, required: message_requeued: the agent was interrupted before answering, so the message goes back to the inbox and starts again on a fresh environment.
            - `message_id` string, required
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'message_requeued', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - EnvironmentPhaseRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` EnvironmentPhasePayload, required: environment_phase: one transition of environment preparation, so clients can narrate progress live and locate failures. Phases are an OPEN vocabulary; `detail` carries phase-specific extras additively.
            - `detail` object, nullable
            - `duration_ms` integer, nullable
            - `phase` string, required
            - `status` string, required
            - `step` string, nullable
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'environment_phase', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - EnvironmentOutputRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` EnvironmentOutputPayload, required: environment_output: one chunk of output from preparing the environment, including the customer's own hooks. Many fire per message; `chunk` orders them within a step.
            - `chunk` integer, required
            - `lines` string[], required
            - `phase` string, required
            - `step` string, nullable
            - `stream` string
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'environment_output', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
        - EnvironmentReadyRecord
          - `cost` integer, nullable, required
          - `created_at` string, date-time, required
          - `duration` integer, nullable, required
          - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
          - `id` string, required: Unique identifier of the record.
          - `kind` 'platform', required
          - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
          - `model` string, nullable, required
          - `payload` EnvironmentReadyPayload, required: environment_ready: the environment is prepared and the agent is about to start.
            - `duration_ms` integer, nullable
            - `repositories` string[], required
          - `record_format` 'ellipsis_lifecycle@1', required
          - `record_type` 'environment_ready', required
          - `session_id` string, required: Session containing this record.
          - `source` 'lifecycle', required
          - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
            - `cache_creation_input_tokens` integer
            - `cache_read_input_tokens` integer
            - `cost_usd` number
            - `input_tokens` integer
            - `num_turns` integer
            - `output_tokens` integer
          - `tools` string[], nullable, required
      - UnknownSessionRecord: Unrecognized or unparseable payload; the complete original stays readable.
        - `cost` integer, nullable, required
        - `created_at` string, date-time, required
        - `duration` integer, nullable, required
        - `feed_seq` integer, required: Position in the session feed and the stream's resume cursor.
        - `id` string, required: Unique identifier of the record.
        - `kind` 'unknown', required
        - `message_id` string, nullable, required: The message this record belongs to: the message itself, or what happened while answering it. Null for records outside any message, such as the session closing.
        - `model` string, nullable, required
        - `payload` object, required
        - `record_format` string, required: Original versioned payload format.
        - `record_type` string, required: Original record type within its format.
        - `session_id` string, required: Session containing this record.
        - `source` string, required: Original producer. Unknown producers remain readable as unknown records.
        - `tokens_info` TokensInfo, required: Token/cost usage, per record (one API call's counts, aggregate fields at their zero defaults) or aggregated per turn/session (compute_spend_from_records derives num_turns and cost_usd). Strict on purpose: this is our own persisted schema, so an unknown key is a writer bug (the num_turns=0 bug shipped because a Claude Code usage dict validated leniently against this model, silently zeroing every non-overlapping field). Legacy keys were dropped from persisted blobs by the 2026-07-26 tokens_info migration; per-model usage (CC's modelUsage, verbatim) is stored separately, not here.
          - `cache_creation_input_tokens` integer
          - `cache_read_input_tokens` integer
          - `cost_usd` number
          - `input_tokens` integer
          - `num_turns` integer
          - `output_tokens` integer
        - `tools` string[], nullable, required

## Other responses

- `401`: The bearer token is missing, invalid, or revoked.
- `403`: The credential may not perform this action, or the account is blocked.
- `404`: No such session in your account.
- `422`: Validation Error

---

[API](https://skmtc.dev/ellipsis/apis/ellipsis-rest-api.md) - [All operations](https://skmtc.dev/ellipsis/apis/ellipsis-rest-api/llms.txt) - [OpenAPI document](https://skmtc.dev/ellipsis/apis/ellipsis-rest-api/revisions/344b16df9a1a?raw)
