---
title: "Get a generation's transcript"
method: GET
path: "/v1/projects/{project_id}/generations/{generation_id}/transcript"
tags: ["Generations"]
---

# Get a generation's transcript

`GET /v1/projects/{project_id}/generations/{generation_id}/transcript`

## Request

- Base URL: `https://api.naturali.ai`
- URL: `https://api.naturali.ai/v1/projects/{project_id}/generations/{generation_id}/transcript`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.naturali.ai/authorize`, token URL `https://api.naturali.ai/token`, scopes: `mcp:access`)

Returns one generation's turn read back as an ordered sequence of steps: what it was asked, each model step with its tool calls and results, and how it ended.

The transcript is assembled at read time from the generation record and the trace's steps object; nothing is stored, so it cannot outlive the content it projects. Requires `traces:GetTrace` in addition to `generations:GetGeneration`, because the response merges content from both resources.

A generation whose content is unavailable — never written under zero-retention, or cleared by a purge — returns `200` with the skeleton rather than an error: `input` and `output` are null, `steps` is empty, and the `content_redacted_*` fields say which happened. `content_redacted_by_principal_id` is `zero_retention` when the content was never stored, and the purging principal's ID when it was erased later. A generation that is still running returns the same shape with an empty `steps`; `status` disambiguates the two.

## Path parameters

- `generation_id` string, required

## Response `200`

The generation's transcript

- GenerationTranscript: One generation's turn, read back step by step. Assembled at read time from the generation record and the trace's steps object — never stored, so it dies with the content it projects.
  - `generation_id` string
  - `trace_id` string, nullable
  - `project_id` string
  - `agent_id` string
  - `agent_version` integer, nullable: Agent config version that served the turn.
  - `status` 'running' | 'requires_action' | 'completed' | 'failed': Lifecycle status of the generation. Disambiguates an empty `steps` caused by a run still in flight from one caused by erased content.
  - `stop_reason` string, nullable: Why the generation stopped — the provider's finish reason, or one of the platform's own ('max_steps', 'depth_guard', 'chain_limit', 'error').
  - `started_at` string, date-time
  - `completed_at` string, date-time, nullable
  - `step_count` integer: Number of steps this turn recorded. A counter rather than content, so it survives a purge and still reports the size of a turn whose steps are gone. Scoped to the generation, not the trace: a trace that groups several generations counts them all in its own `step_count`, while each transcript reports only its own.
  - `input` object[], nullable: The messages the turn was asked, as recorded. Message content is caller-owned and passed through verbatim. Null when the content was never stored or has been purged.
  - `steps` TranscriptStep[]: The turn's steps in order. Empty for a run still in progress, and for one whose content is unavailable — `status` and `content_redacted_at` say which.
    - `index` integer: Zero-based position of this step in the turn. Positional rather than the model's own step number, which restarts at zero when a paused turn resumes.
    - `text` string: The text this step produced. Empty for a step that only called tools.
    - `finish_reason` string, nullable: Why this step stopped.
    - `tool_calls` TranscriptToolCall[]
      - `id` string, nullable: The call's ID, as the model provider issued it (e.g. `call_…`), used to correlate it with an entry in `tool_results`. Null when the stored step did not record one.
      - `tool_name` string, nullable
      - `args` unknown
    - `tool_results` TranscriptToolResult[]
      - `tool_call_id` string, nullable: The `id` of the `tool_calls` entry this answers.
      - `tool_name` string, nullable
      - `result` unknown
      - `error` StoredError: Why a resource's work failed, in the shape of an error response's `error` without `hint` and `docs_url`. Every `error` field a resource records carries it, so `code` can be read without first checking the type of `error`.
        - `code` string, required: A key from the server's ERROR_CODES registry, documented on the Error Codes page. `INTERNAL_ERROR`, with the message `Internal Server Error`, records an unexpected failure whose detail reaches the server log only.
        - `message` string, required
        - `meta` object: The failure's own structured context, when it names any.
    - `usage` UsageTotals: Token counts and cost for one slice of the meter. Tokens and cost only: a `compute_second` or `gb_day` meter is reported by the aggregate's `components` array. The three input dimensions partition the prompt — `input_tokens` = `uncached_input_tokens` + `cached_tokens` + `cache_write_tokens` — and are separate because they are separately priced. Note that the `input_tokens` **component** on a usage event is the uncached figure alone; here `input_tokens` is the whole prompt.
      - `cost_usd` number, nullable: Sum of priced component costs; null when nothing in the slice was priced. Always null at step altitude — the ledger prices one event per generation at write time, and a price read back per step would disagree with it after any price change.
      - `input_tokens` integer: Full prompt tokens, reconstructed from the components.
      - `uncached_input_tokens` integer: Prompt tokens priced at the plain input rate — the prompt minus cache reads and cache writes.
      - `output_tokens` integer
      - `cached_tokens` integer: Prompt tokens served from the provider's prompt cache.
      - `cache_write_tokens` integer: Prompt tokens written into the provider's prompt cache.
      - `reasoning_tokens` integer: A non-billable subset of `output_tokens`, reported where the provider breaks it out.
  - `output` object, nullable: The turn's final answer. Null when there are no steps to derive it from.
    - `content` string, nullable: The last step that produced text. Null for a turn that only called tools.
    - `finish_reason` string, nullable: The finish reason of the actual last step.
  - `error` StoredError: Why a resource's work failed, in the shape of an error response's `error` without `hint` and `docs_url`. Every `error` field a resource records carries it, so `code` can be read without first checking the type of `error`.
    - `code` string, required: A key from the server's ERROR_CODES registry, documented on the Error Codes page. `INTERNAL_ERROR`, with the message `Internal Server Error`, records an unexpected failure whose detail reaches the server log only.
    - `message` string, required
    - `meta` object: The failure's own structured context, when it names any.
  - `content_redacted_at` string, date-time, nullable: When the generation's content was erased; null while it is intact.
  - `content_redacted_by_principal_type` 'user' | 'api_key' | 'agent' | 'automation' | 'approval' | 'system': What kind of principal acted. `user` and `api_key` are authenticated callers, and the id is the user's (`user_…`) or the key's own (`key_…`), so a record names which key acted rather than its owner. `agent` is an agent writing under its own identity (`agent_…`). `automation` is the task engine acting on a dispatch outcome and `approval` an approval resolution; neither carries an id. `system` is the platform itself, with an id naming the mechanism (`retention_sweep`, `zero_retention`).
  - `content_redacted_by_principal_id` string, nullable: Public id of that principal. `zero_retention` when the content was never stored, distinguishing it from content erased later.

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Generation not found

---

[API](https://skmtc.dev/naturali/apis/naturali-ai-api.md) · [All operations](https://skmtc.dev/naturali/apis/naturali-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/naturali/apis/naturali-ai-api/revisions/e4905b78f422?raw)
