# Hosted render frame

Returns isolated creative HTML for a single asset token.

The hosted renderer creates an iframe for this route. Customer frontends should not construct this URL manually in the default flow; use placement.render.frame_url.

| Method | Path | Authentication | Stability |
| --- | --- | --- | --- |
| GET | /v1/render/{asset_token} | Asset token in the path | stable |

## Request fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| asset_token | string | Yes | Asset token from placement.render.frame_url or placement.asset_token. |

## Response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| html | text/html | Yes | Isolated creative frame with strict CSP and no-store/private caching. |

## Errors

| Status | Code | Description |
| --- | --- | --- |
| 404 | not_found | Asset token is invalid, expired, or not renderable. |
| 403 | forbidden | Asset token is not authorized for the requested creative context. |

## Response example

```json
<!doctype html><html><body><img alt="Sponsored placement" /></body></html>
```

## cURL

```bash
curl "https://api.wavebird.ai/v1/render/wbat_asset_demo" \
  -H "Accept: text/html"
```

## Node

```javascript
const response = await fetch("https://api.wavebird.ai/v1/render/wbat_asset_demo", {
  headers: { Accept: "text/html" }
});

console.log((await response.text()).slice(0, 80));
```

## Python

```python
import urllib.request

request = urllib.request.Request(
    "https://api.wavebird.ai/v1/render/wbat_asset_demo",
    headers={"Accept": "text/html"},
)

with urllib.request.urlopen(request) as response:
    print(response.read().decode("utf-8")[:80])
```
