> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryblend.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Output Parts

> Every workflow result is an array of output items, and every item contains typed parts.

When a published run completes, `GET /api/v1/runs/{runId}` returns an `output` object keyed by the normalized label of each User Result node.

Each key maps to an **array of output items**. Each output item preserves one logical unit of work: one normal run, one batch iteration, one selected item, or one element from an LLM structured list.

```json theme={null}
{
    "output": {
        "caption": [
            {
                "id": "item_1",
                "item_index": 0,
                "status": "completed",
                "parts": [
                    { "type": "text", "text": "A cat on the moon, gazing at earth." }
                ]
            }
        ],
        "image": [
            {
                "id": "item_2",
                "item_index": 0,
                "status": "completed",
                "parts": [
                    { "type": "image", "url": "https://cdn.tryblend.ai/runs/abc/image.png" }
                ]
            }
        ]
    }
}
```

## Output items

| Field        | Type                                           | Notes                                                                               |
| ------------ | ---------------------------------------------- | ----------------------------------------------------------------------------------- |
| `id`         | `string`                                       | Stable item id.                                                                     |
| `item_index` | `number`                                       | Ordered item position, starting at `0`.                                             |
| `status`     | `completed` / `failed` / `pending` / `running` | Completed API output usually contains completed or failed items.                    |
| `parts`      | `OutputPart[]`                                 | The content fragments inside this item.                                             |
| `error`      | `object?`                                      | Present when the item failed. Contains `message`, and may include `type` or `code`. |

Why an array of items? A Result can receive multiple logical outputs: a Batch with five rows, a multi-select Choose Output, or an LLM structured list with several elements. Each logical output stays separate.

Why can one item contain multiple parts? One provider call can produce several fragments, such as text plus a file, or several files from one generation call.

## Part types

Check `part.type` and branch on it.

<AccordionGroup>
  <Accordion title="text" icon="align-left">
    Plain string output — chat responses, captions, summaries, transcriptions.

    ```json theme={null}
    { "type": "text", "text": "A cat on the moon, gazing at earth." }
    ```

    | Field  | Type     | Notes        |
    | ------ | -------- | ------------ |
    | `text` | `string` | The content. |
  </Accordion>

  <Accordion title="image" icon="image">
    An image file hosted on Blend AI's CDN.

    ```json theme={null}
    {
        "type": "image",
        "url": "https://cdn.tryblend.ai/runs/abc/image.png",
        "name": "image.png"
    }
    ```

    | Field  | Type      | Notes                 |
    | ------ | --------- | --------------------- |
    | `url`  | `string`  | Direct CDN URL.       |
    | `name` | `string?` | File name when known. |
  </Accordion>

  <Accordion title="video" icon="video">
    A video file hosted on Blend AI's CDN.

    ```json theme={null}
    {
        "type": "video",
        "url": "https://cdn.tryblend.ai/runs/abc/video.mp4",
        "name": "video.mp4"
    }
    ```

    | Field  | Type      | Notes                 |
    | ------ | --------- | --------------------- |
    | `url`  | `string`  | Direct CDN URL.       |
    | `name` | `string?` | File name when known. |
  </Accordion>

  <Accordion title="file" icon="file">
    Any non-image, non-video file, including audio, PDFs, documents, or archives.

    ```json theme={null}
    {
        "type": "file",
        "url": "https://cdn.tryblend.ai/runs/abc/audio.mp3",
        "name": "audio.mp3",
        "mime_type": "audio/mpeg"
    }
    ```

    | Field       | Type      | Notes                 |
    | ----------- | --------- | --------------------- |
    | `url`       | `string`  | Direct CDN URL.       |
    | `name`      | `string?` | File name when known. |
    | `mime_type` | `string?` | MIME type when known. |
  </Accordion>

  <Accordion title="json" icon="braces">
    Structured JSON data returned by a workflow output.

    ```json theme={null}
    {
        "type": "json",
        "data": {
            "title": "Moon Cat",
            "score": 0.92
        }
    }
    ```

    | Field  | Type      | Notes                 |
    | ------ | --------- | --------------------- |
    | `data` | `unknown` | The structured value. |
  </Accordion>
</AccordionGroup>

## Reading parts in your code

<CodeGroup>
  ```ts TypeScript theme={null}
  type OutputPart =
      | { type: 'text'; text: string }
      | { type: 'image' | 'video'; url: string; name?: string }
      | { type: 'file'; url: string; name?: string; mime_type?: string }
      | { type: 'json'; data: unknown }

  type OutputItem = {
      id: string
      item_index: number
      status: 'completed' | 'failed' | 'pending' | 'running'
      parts: OutputPart[]
      error?: { message?: string; type?: string; code?: number }
  }

  function renderPart(part: OutputPart): string {
      switch (part.type) {
          case 'text': return part.text
          case 'image': return `![](${part.url})`
          case 'video': return `<video src="${part.url}" />`
          case 'file': return part.url
          case 'json': return JSON.stringify(part.data)
      }
  }
  ```

  ```python Python theme={null}
  def render_part(part: dict) -> str:
      kind = part["type"]
      if kind == "text":
          return part["text"]
      if kind in ("image", "video", "file"):
          return part["url"]
      if kind == "json":
          return str(part["data"])
      return ""
  ```
</CodeGroup>

## Duplicate labels

If two User Result nodes share the same normalized label, publishing asks you to rename one of them. Explicit labels keep your runner and API contract stable across workflow edits.

## What's next

<CardGroup cols={2}>
  <Card title="Lists & single values" icon="list-tree" href="/concepts/lists-and-values">
    How batches, selections, and structured lists become multiple output items.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/overview">
    Full endpoint reference with request/response schemas and a live playground.
  </Card>
</CardGroup>
