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

# Get Result Image

> Stream a PNG/JPEG visual image referenced by an extraction
response under `bounding_boxes.Images[].image_url`.

The URL is API-hosted instead of raw S3 — the underlying object
store is intentionally not part of the public contract. The host
in `image_url` mirrors the request origin (e.g. a request to a
beta deployment returns image URLs on that same host).

**Authentication is required.** Unlike single-use result download
links, visual artifacts are
independently-addressable resources — every fetch must present a
valid API key for the owning org. There is no anonymous /
TTL-based fallback. Use the same `x-api-key` header you use for
`/extract`.

Fetching an image does **not** consume the parent extraction's
result-delivery slot, so one extraction can produce many image
URLs and each can be fetched repeatedly while the artifact is
retained.

## Overview

Fetch a PNG or JPEG visual image referenced by an extraction response under `bounding_boxes.Images[].image_url`.

When you call [`/extract`](/api-reference/endpoint/extract) with `figure_processing.show_images: true`, every detected chart or embedded image in the response carries an `image_url` field. Those URLs point at this endpoint — `GET /results/{jobId}/images/{filename}` — which streams the actual image bytes.

```json theme={null}
{
  "bounding_boxes": {
    "Images": [
      {
        "id": "excel_image_1_1",
        "visual_type": "chart",
        "image_url": "https://api.runpulse.com/results/13e3e75f-.../images/excel_image_1_1.png",
        "chart_type": "BarChart",
        "chart_title": "Revenue",
        "excel_range": "D2",
        "sheet_name": "Charts"
      }
    ]
  }
}
```

<Note>
  This endpoint is most useful for **spreadsheet** extractions, where charts and embedded images are read directly from the workbook. For PDFs and image inputs, the same shape applies whenever figure detection is enabled.
</Note>

## When to use this vs. `/large_results/{jobId}`

| Endpoint                                 | Purpose                                                                                                                    | Auth                                                   | Single-use?                                                          |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------- |
| `GET /large_results/{jobId}`             | Download the **full extraction result** (markdown + bounding\_boxes + …) when the inline payload exceeds 5 MB or 70 pages. | Anonymous within 1-hour TTL or authenticated same-org. | Yes — fetching invalidates the link.                                 |
| `GET /results/{jobId}/images/{filename}` | Download **one visual image** referenced by `bounding_boxes.Images[].image_url`.                                           | Authenticated same-org only. No anonymous access.      | No — fetch as many times as you need while the artifact is retained. |

Fetching a visual image **does not** consume the parent extraction's result-delivery slot, because a single extraction can contain many image URLs.

## End-to-End Example

The full path: extract a workbook → walk the typed `Images` array → fetch one chart's bytes.

<CodeGroup>
  ```python Python theme={null}
  from pulse import Pulse
  from pulse.types import ExtractRequestFigureProcessing

  client = Pulse(api_key="YOUR_API_KEY")

  # 1) Extract a workbook and ask for image URLs.
  response = client.extract(
      file=open("financials.xlsx", "rb"),
      figure_processing=ExtractRequestFigureProcessing(
          show_images=True,
          description=False,
      ),
  )

  # 2) Walk the typed Images array.
  for img in response.bounding_boxes.images or []:
      print(img.id, img.visual_type, img.chart_title, img.image_url)

  # 3) Fetch the bytes for the first chart.
  import re

  img = response.bounding_boxes.images[0]
  m = re.search(r"/results/([^/]+)/images/([^/?#]+)", img.image_url)
  job_id, filename = m.group(1), m.group(2)

  # `get_image` returns an iterator of byte chunks — join to get the full PNG.
  chunks = list(client.results.get_image(job_id=job_id, filename=filename))
  png_bytes = b"".join(chunks)

  with open("chart.png", "wb") as f:
      f.write(png_bytes)
  ```

  ```typescript TypeScript theme={null}
  import { PulseClient } from "pulse-ts-sdk";
  import * as fs from "node:fs";

  const client = new PulseClient({ apiKey: "YOUR_API_KEY" });

  // 1) Extract a workbook and ask for image URLs.
  const response = await client.extract({
      file: fs.createReadStream("financials.xlsx"),
      figureProcessing: { showImages: true },
  });

  // 2) Walk the typed Images array.
  for (const img of response.boundingBoxes?.Images ?? []) {
      console.log(img.id, img.visualType, img.chartTitle, img.imageUrl);
  }

  // 3) Fetch the bytes for the first chart.
  const url = response.boundingBoxes?.Images?.[0]?.imageUrl;
  const m = url?.match(/\/results\/([^/]+)\/images\/([^/?#]+)/);
  const [, jobId, filename] = m!;

  const image = await client.results.getImage({ jobId, filename });
  // image is a binary response — consume per your runtime (e.g. `await image.bytes()`).
  ```

  ```bash curl theme={null}
  # Step 1: extract and capture the image_url.
  curl -sS -X POST https://api.runpulse.com/extract \
    -H "x-api-key: $PULSE_API_KEY" \
    -F "file=@financials.xlsx" \
    -F 'figure_processing={"show_images": true}' \
    | jq -r '.bounding_boxes.Images[0].image_url'
  # -> https://api.runpulse.com/results/13e3e75f-.../images/excel_image_1_1.png

  # Step 2: fetch the PNG bytes.
  curl -sS -X GET "https://api.runpulse.com/results/13e3e75f-.../images/excel_image_1_1.png" \
    -H "x-api-key: $PULSE_API_KEY" \
    -o chart.png
  ```
</CodeGroup>

## Authentication

**Every request must present a valid `x-api-key` header for the org that owns the extraction.** Unlike the legacy single-use `/large_results/{jobId}` route, visual artifacts are independently-addressable resources — there is no anonymous fallback or short-lived public link.

* **Authenticated same-org calls** (your `x-api-key` matches the org that produced the extraction): succeed for as long as the underlying artifact is retained — same window as any other extraction artifact for that org.
* **Missing credentials** (no `x-api-key` header): rejected with `401 Unauthorized` (`AUTH_001`).
* **Cross-org authenticated calls** (valid key, but not the owning org): rejected with `403 Forbidden` (`AUTH_002`).

Use the same key configuration as your other Pulse SDK calls — the SDK's `Pulse(api_key=...)` / `new PulseClient({ apiKey: ... })` constructor will attach `x-api-key` to every `results.getImage` fetch automatically.

<Warning>
  Embedding `image_url` directly in **public** UIs (e.g. a server-rendered HTML page exposed to unauthenticated visitors) will fail with `401`. For public/anonymous embeds, fetch the bytes server-side using your API key and re-host them, or proxy them through your own auth layer.
</Warning>

<Note>
  Repeated fetches against the same `image_url` are fine — the link is multi-use. Fetching does **not** consume the parent extraction's result-delivery slot, so one extraction can produce many image URLs and each can be downloaded as many times as needed.
</Note>

## Errors

| Status             | Code              | Meaning                                                                                                        |
| ------------------ | ----------------- | -------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`  | `INVALID_REQUEST` | The `filename` path segment failed safe-filename validation.                                                   |
| `401 Unauthorized` | `AUTH_001`        | No `x-api-key` (or no valid signed-in session) was supplied.                                                   |
| `403 Forbidden`    | `AUTH_002`        | The caller is authenticated but does not belong to the org that owns this extraction.                          |
| `404 Not Found`    | `NOT_FOUND`       | Job or visual image not found. The `jobId` or `filename` is wrong, or the artifact has been garbage-collected. |

## Next Steps

<CardGroup cols={2}>
  <Card title="Bounding Boxes" icon="vector-square" href="/api-reference/bounding-boxes">
    Full reference for the `Images`, `Tables`, `Text`, `Title`, and `Footer` arrays.
  </Card>

  <Card title="Extract Endpoint" icon="code" href="/api-reference/endpoint/extract#excel-charts-and-embedded-images">
    Enable `figure_processing.show_images` to populate `image_url`.
  </Card>
</CardGroup>


## OpenAPI

````yaml GET /results/{jobId}/images/{filename}
openapi: 3.1.0
info:
  title: Pulse API Structure
  version: 0.1.0
  description: >-
    Canonical contract for the Pulse extraction APIs. This specification is the
    single source of truth for shared request/response models that client and
    server packages consume.
servers:
  - url: https://api.runpulse.com
    description: Default Pulse API base URL
security:
  - ApiKey: []
paths:
  /results/{jobId}/images/{filename}:
    get:
      tags:
        - Results
      summary: Download an extraction visual image
      description: |-
        Stream a PNG/JPEG visual image referenced by an extraction
        response under `bounding_boxes.Images[].image_url`.

        The URL is API-hosted instead of raw S3 — the underlying object
        store is intentionally not part of the public contract. The host
        in `image_url` mirrors the request origin (e.g. a request to a
        beta deployment returns image URLs on that same host).

        **Authentication is required.** Unlike single-use result download
        links, visual artifacts are
        independently-addressable resources — every fetch must present a
        valid API key for the owning org. There is no anonymous /
        TTL-based fallback. Use the same `x-api-key` header you use for
        `/extract`.

        Fetching an image does **not** consume the parent extraction's
        result-delivery slot, so one extraction can produce many image
        URLs and each can be fetched repeatedly while the artifact is
        retained.
      operationId: getResultImage
      parameters:
        - name: jobId
          in: path
          required: true
          description: >-
            Job identifier — same value used in the `image_url` returned from
            `/extract`.
          schema:
            type: string
        - name: filename
          in: path
          required: true
          description: >-
            Visual filename — e.g. `excel_image_1_1.png`. Must be the exact
            `filename` segment from the `image_url`.
          schema:
            type: string
      responses:
        '200':
          description: Visual image bytes (`image/png` or `image/jpeg`).
          content:
            image/png:
              schema:
                type: string
                format: binary
            image/jpeg:
              schema:
                type: string
                format: binary
        '400':
          description: Invalid artifact filename.
        '401':
          description: >-
            Authentication required. Returned whenever no API key (or no valid
            signed-in session) accompanies the request. Visual artifacts always
            require same-org authentication.
        '403':
          description: >-
            Authenticated caller is not allowed to access this org's visual
            image (cross-org access is rejected).
        '404':
          description: Job or visual image not found.
        '500':
          description: Internal server error
components:
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: x-api-key
      x-fern-header:
        name: apiKey
        env: PULSE_API_KEY

````