> Public copy of the ViewStream developer guide (also for AI agents). All guides: https://www.viewstream.co.il/developers/guide/index.md · API reference: https://api.viewstream.co.il/docs/

# Sites Delivery API

The Sites Delivery API is the **public, read-only, cacheable** API behind ViewStream Sites. The hosted site renderer
uses it; you can use it too, to build your own front end (web, app, smart TV) on the content you manage in Studio →
Sites.

- Base: `https://api.viewstream.co.il/s/v1/{site}/…` — `{site}` is the site's slug (Studio → **Sites**).
- No API key. Only published content is returned (drafts need a preview token).
- Its own OpenAPI document: `https://api.viewstream.co.il/openapi/sites-delivery.yaml` (pick **Sites Delivery API**
  on `/docs/`).
- Sources: routes in sites/delivery.go; behaviour described in
  sites.md; product brief
  viewstream-sites-spec.md.

The management side (editing sites, pages, shows, people, menus, theme) is the normal `/v1` API with the `sites:*`
scopes — see [getting-started.md](getting-started.md#3-scopes).

## Routes

| Route | Returns |
|---|---|
| `GET /s/v1/{site}/config` | The site: theme tokens, published menus, dictionary, scripts, consent, accessibility, SEO, the player (`tenant`, `config`, `cdn_hostname`), EPG settings, time zone, AI-crawler mode |
| `GET /s/v1/{site}/route?path=/show/evening-news` | What a path is: `{kind: page \| template \| redirect \| not_found, page_id?, template_for?, entity?, redirect?}`. Order: redirects, page paths, the site's route table, then built-ins (`/show/:slug`, `/podcast/:slug`, `/v/:slug`, `/c/:slug`, `/p/:slug`, `/live/:slug`, `/person/:slug`, `/category/:slug`, `/search`, `/epg`) |
| `GET /s/v1/{site}/pages/{id}?sections=5[&entity=type:slug][&preview=<token>]` | The page version on air now, the first N sections resolved (`items`, `more`), `next_cursor`, the entity for templates |
| `GET /s/v1/{site}/pages/{id}/sections?cursor=&count=` | The next sections of a page |
| `GET /s/v1/{site}/entities/{type}/{slug}` | One item (show, video, clip, programme, channel, person …) with `playback {mode, src, tenant, channel?, kind}`, a channel's `now`/`next`, series and people; programmes and videos also carry `article` once an editor published their AI article (`headline`, `standfirst`, `summary`, `chapters`, `quotes` with `start_ms`, `entities`, `tags`, `label`, `reviewed`) — never a draft |
| `GET /s/v1/{site}/epg?channel=&day=YYYY-MM-DD` | One day of the guide (day in `Asia/Jerusalem`) with `catchup`, `start_over`, `start_over_src`, `series`; published channels only |
| `GET /s/v1/{site}/search?q=&type=&cursor=` | Hebrew-aware search over shows, videos and catch-up programmes |
| `GET /s/v1/{site}/suggest?q=` | Up to 8 quick suggestions |
| `GET /s/v1/{site}/sitemap/{index\|pages\|shows\|videos\|programmes}.xml` | Sitemaps (video sitemap for videos, clips and catch-up) |
| `GET /s/v1/{site}/robots` | The site's robots.txt |
| `GET /s/v1/{site}/podcast/{slug}/feed.xml` | A show's podcast RSS feed |
| `GET /s/v1/_host?…` | Custom domain → site slug (used by the renderer) |

## Availability rules

- A programme offers **catch-up** when it has ended, started inside the channel's retention and after the channel's
  first recorded minute, and is not excluded by a catch-up exclusion rule.
- **Start-over** is offered while the programme is on air, if its start is recorded.
- Videos appear when `ready` and published; clips when `ready` or `final`.

## Images

Items carry `images` with WebP URLs per preset: `tile_16x9` (640×360), `tile_16x9_320` (320×180, the phone candidate),
`tile_1x1`, `tile_2x3`, `poster` (1280×720), `hero_16x9` (1920×1080), `title_art`. Every key is optional — fall back to
`tile_16x9`. A suggested `srcset`: `tile_16x9_320 320w, tile_16x9 640w, poster 1280w`.

## Caching

| Header | Value |
|---|---|
| `Cache-Control` | `public, s-maxage=30, stale-while-revalidate=300, stale-if-error=86400` (sitemaps 600 s, robots 3600 s; preview answers `private, no-store`) |
| `ETag` | send `If-None-Match` for `304` |
| `Cache-Tag` | `site:<id>, page:<id>, entity:<type>:<id>…` (used for purging) |
| `X-VS-Sites-API` | `1` — the API version |
| CORS | allowed for the site's own hostnames and Studio |

A page with a scheduled change caps `s-maxage` at the moment of that change, so the switch is on time.

## Errors

Errors are `application/problem+json` with `Cache-Control: no-store`. A suspended or unknown site answers `404`
(`"no such site"`). When Sites is not enabled on a deployment every route answers `503`.

Note: the `type` URIs here are derived from the HTTP status text (`…/problems/not-found`), not the `snake_case` codes
of the main API (`…/problems/not_found`) — see known gaps.

## Web components

Ready-made tiles and player elements for your own pages: `@viewstream/sites-wc`
(`https://player.viewstream.co.il/sdk/sites-wc@0.2.4.js`, demo `/sdk/demo.html`; documentation in
studio/packages/sites-wc/README.md). See also
[player-integration.md](player-integration.md).
