# Fetch the proof-of-page HTML

> Stream the opt-in proof-of-page HTML for a consumer-UI capture, referenced by an Envelope’s top-level html URL.

`GET /v1/artifacts/:key` streams the **proof-of-page HTML**: a rendered snapshot of the exact consumer-UI page an answer was captured from, so you can show a receipt of what a real user saw. It is **opt-in** — the snapshot is published only when the request set `include.html: true`, and only for **consumer-UI (scrape) surfaces** (the ones with a real page to snapshot). When it exists, the Envelope carries a top-level `html` field: a pre-built link to this endpoint. There is no separate key to assemble — you follow that `html` URL. The internal raw capture blob is never served here.

<Warning>
  This endpoint is **private**. It requires your API key, and a restricted
  `sk_*` key can only read artifacts stamped with its own owner. A mismatch is a
  `404`, never a `403` (no existence leak across tenants). Never expose these
  URLs client-side.
</Warning>

<ParamField path="key" type="string" required>
  The artifact key, **URL-encoded**. You never build this by hand — the
  top-level `html` field in an Envelope is already a full URL that points at
  this endpoint with the key encoded for you.
</ParamField>

## Request

Follow the top-level `html` URL from an Envelope directly. It is present only when you opted in with `include.html: true` on the request and the surface was a consumer-UI capture:

<CodeGroup>

```bash cURL
# The html URL comes straight from the Envelope
curl -L "https://api.aisearchapi.dev/v1/artifacts/job_8t2q.chatgpt.us/call_e9e13810ec46f8bbb814497766d1d05c/page.html" \
  -H "Authorization: Bearer $AISEARCH_API_KEY" \
  -o page.html
```

```javascript Node
// Read the Envelope, then fetch the proof-of-page HTML.
const job = await (
  await fetch('https://api.aisearchapi.dev/v1/jobs/job_8t2q.chatgpt.us', {
    headers: { Authorization: `Bearer ${process.env.AISEARCH_API_KEY}` },
  })
).json();

// `html` is only present when you opted in (include.html: true) on a scrape surface.
if (job.html) {
  const res = await fetch(job.html, {
    headers: { Authorization: `Bearer ${process.env.AISEARCH_API_KEY}` },
  });
  const html = await res.text();
}
```

```python Python
import os, requests

headers = {"Authorization": f"Bearer {os.environ['AISEARCH_API_KEY']}"}

job = requests.get(
    "https://api.aisearchapi.dev/v1/jobs/job_8t2q.chatgpt.us",
    headers=headers,
).json()

# `html` is only present when you opted in (include.html: true) on a scrape surface.
html_url = job.get("html")
if html_url:
    res = requests.get(html_url, headers=headers)
    html = res.text
```

</CodeGroup>

<Note>
  Opt in at request time — set `include.html: true` on the submit body, or add
  `?include=html` when you poll. If the field is absent, the surface wasn't a
  consumer-UI capture or you didn't opt in, and there is nothing to fetch.
</Note>

## Response

`200 OK` streams the HTML snapshot with the **stored content type** and an `ETag`:

| Artifact               | Typical content type |
| ---------------------- | -------------------- |
| Proof-of-page snapshot | `text/html`          |

Artifacts are retained durably, **not** expired at 24 hours, so the `html` URL keeps resolving for as long as you need it.

## Errors

<ResponseField name="401" type="AUTH_INVALID">
  Missing or invalid API key.
</ResponseField>

<ResponseField name="404" type="ARTIFACT_NOT_FOUND">
  The key doesn't exist, or it belongs to another tenant.
</ResponseField>

```json 404
{
  "code": "ARTIFACT_NOT_FOUND",
  "error": "no artifact for key 'job_8t2q.chatgpt.us/call_e9e13810ec46f8bbb814497766d1d05c/page.html'",
  "request_id": "req_9f2c1a7e4b5d48f1a3c6e8d0b2a4f6c8",
  "docs_url": "https://docs.aisearchapi.dev/guides/errors#artifact_not_found"
}
```

<CardGroup cols={2}>
  <Card title="The Envelope" icon="box" href="/guides/output-formats">
    Where the opt-in `html` proof-of-page URL comes from.
  </Card>
  <Card title="Jobs & polling" icon="clock" href="/api-reference/get-job">
    Read a completed job's Envelope.
  </Card>
</CardGroup>
