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

# Import a catalog

> Bring your own video platform's catalog into AgentTV by your own video ids, and keep it in sync.

The catalog import reads your video ids from your video sitemap or JSON Feed, reads each video's details from your metadata API, and stores each video under your own id. That id is what your page template uses later to fetch the [page block](https://docs.agentcdn.com/guides/page-metadata.md).

Videos keep playing from your stream. AgentTV copies one rendition, the tallest at or under 1080p, into private storage for analysis only: transcript, chapters, moments and the rest. It remuxes and never re-encodes. It never serves that copy to viewers. Every play uses your player or your stream. The only file that leaves it is a [range link](https://docs.agentcdn.com/guides/moment-rails.md#need-a-file-of-one-range) your own team asks for with its key.

To start, AgentTV needs only your video ids and a way to read each video. Everything else, from chapters to people on screen, is derived from the video.

## Two ways to connect

> [tab] Platform import (sitemap plus API)
>
> For a brand with its own video platform and metadata API. You send us the details below, and AgentTV sets up the mapping for your account. The mapping is configuration, not custom code.

> [tab] Website sitemap (self serve)
>
> For a site whose video sitemap already lists each video's HLS stream. You connect it yourself in the console: **Imports**, then the **Video catalog** card. Your site must be verified first under **Website setup**, and the sitemap must be on that domain or a subdomain of it. Each video imports from its `video:content_loc` when that is an HLS stream (`.m3u8`) on one of your allowed stream hosts.

## What you provide

The import reads a list of your videos (a video sitemap or a JSON Feed) plus your metadata API.

### 1. Your video sitemap

A standard video sitemap, or a sitemap index of them. Tell us:

* **The sitemap URL.** It must be https. Child sitemaps must be on the same host.
* **Where the id sits.** Either in the page URL (`<loc>`) or in the player URL (`<video:player_loc>`).
* **A pattern for the id.** A regular expression with one capture group that pulls your id out of that URL. Entries it does not match are skipped.

From each entry, AgentTV reads the title, description, publish date (`video:publication_date`), `lastmod`, duration and thumbnail when present. Publish dates help AI apps judge how fresh a video is, so include them.

Large sitemaps are fine. AgentTV reads the sitemap in the background into a stored index and reads it again every 12 hours. Nothing waits on a live sitemap read.

If your sitemap gives each video a `video:title`, search in the console covers your whole catalog at once.

### A JSON Feed instead of a sitemap

In place of a sitemap, the list can be a [JSON Feed 1.1](https://jsonfeed.org/version/1.1). AgentTV tells the two apart by the document. Each item is one video:

| Item field | What AgentTV reads |
| - | - |
| `id` | Your video id. No id pattern is needed. |
| `url` (else `external_url`) | The video's page. |
| `date_modified` | When the item changed. A moved date reads the item again. |
| `title`, `summary`, `image`, `date_published` | Shown in the console browse. The import itself takes its details from your metadata API. |
| `language` (item, else feed) | The language of the video's title, description and page. |
| `attachments[].url` ending in `.m3u8` | The HLS stream, with its `duration_in_seconds`, for a source with no metadata API. |

Three optional fields go under an `_agentcdn` object on the item:

```json theme={null}
{
  "id": "1234",
  "url": "https://www.example.com/videos/1234",
  "title": "Final day replay",
  "date_modified": "2026-10-30T18:00:00Z",
  "language": "en",
  "_agentcdn": {
    "default_audio_language": "es",
    "window": { "start": 3600, "end": 9000 },
    "expires": "2026-11-23T08:20:25Z"
  }
}
```

* `default_audio_language` is the language the video is spoken in (BCP 47). It holds until the transcript detects the language. It can differ from `language`: an English page for a video spoken in Spanish. See [Languages](https://docs.agentcdn.com/concepts/languages.md).
* `window` is the one time range of the video to import, in seconds of the source. The feed owns it: an item with a window imports only that range, and a console pick cannot change it. An item with no window imports whole.
* `expires` is when your licence for the video ends. After it, the video is not played, listed or used in answers. A changed or removed `expires` moves or clears the end on the next read. An `expires` that is not a time keeps the item out of the list.

A feed of several pages names the next one in `next_url`, on the same host. An item with no usable id or page URL is skipped. Caption tracks come from the HLS stream's subtitle renditions.

### 2. Read access to your metadata API

AgentTV reads one item per video from your API. Tell us:

* **The API origin**, for example `https://api.example.com`. Every request and redirect stays on this origin.
* **The item path** with `{id}` where your id goes, for example `/v3/videos/{id}`.
* **Any headers** the API needs, and an optional token step: one call at the start of each run that returns a token for the item reads.
* **Where each field sits** in the response, as a dot path such as `data.attributes.title`:

| Field | Required | Notes |
| - | - | - |
| Title | Yes | |
| Description | No | |
| Duration | No | In seconds, milliseconds or ISO 8601. Leave it out and AgentTV sums the segment lengths in the HLS media playlist. |
| Poster | No | Public https only. Falls back to the sitemap's `video:thumbnail_loc`. |
| Captions | No | Caption tracks the API lists. Subtitle tracks in the HLS playlist are read too. |
| Playback URL | Yes, or a template | See below. |

### 3. The playback URL

Pick one:

* **A field in the API answer** that holds the HLS master playlist URL.
* **A manifest URL template** when your playback URL follows from the id. It is an https URL with `{id}` in the path or query, for example `https://play.example.com/{id}/master.m3u8`. The id is URL-encoded. The host is fixed in the template, so an id can never pick the host.

HLS (HTTP Live Streaming) is the streaming format that uses `.m3u8` playlists.

### 4. Your stream hosts

AgentTV plays and reads streams only from hosts on your account's allow list. Send us each stream host, and each caption host if it differs. Rules:

* https only. No ports, no credentials, no private addresses.
* One account's list never serves another account's video.
* To remove a host later, tell us. Videos on that host stop importing and playing through AgentTV.

> [!NOTE]
>
> AgentTV reads your API and plays your streams only after you give your written OK.

## Pick what to import

Nothing from your back catalog imports on its own. In the console, open **Imports** and the **Video catalog** card. You browse your catalog newest first, search it, and pick videos. One pick takes up to 100 videos. AgentTV copies and processes them in the background.

The account MCP tool `import_catalog_items` (`POST /v1/catalog-source/imports`) does the same. See [Account tools](https://docs.agentcdn.com/reference/account-tools.md).

Each video shows a status:

| Status | Meaning |
| - | - |
| New | Not in your library yet. |
| Queued | Picked and waiting, or still processing. |
| Imported | In your library and ready. |
| Changed | Ready, and the source changed since. Pick it again to refresh it. |
| Failed | Processing stopped. It needs review. |
| Removed | No longer in your catalog. |
| Unavailable | It cannot import. The reason shows next to it. |

## New videos and the daily sync

The day you connect the catalog sets the baseline. Every video listed then is back catalog. A video that first appears after that is a new video.

Once a day, AgentTV reads your catalog again. It refreshes imported videos whose `lastmod` moved, and it handles new videos by your **new video policy**:

| Policy | What the daily sync does |
| - | - |
| `review_first` | New videos wait for you to pick them. This is the default. |
| `automatic` | New videos import on their own. Not available on the starter plan. |
| `off` | No daily sync. The source is paused. |

Under `automatic` and `review_first`, videos you already imported still refresh.

## What is refused

A video does not import when its stream is:

* **Encrypted or DRM protected.** AgentTV cannot read the media.
* **Live.** Only finished video on demand imports. A live slot with no replay shows as "stream not found".
* **Byte-range.** Playlists that address segments by byte range.
* **On a host that is not on your list.**
* **Too large.** The largest copy is 40 GB, enough for a 14 hour replay at 6 Mbps.

AgentTV also refuses a child sitemap on another host, and an API redirect off your API origin.

AgentTV also skips a feed item past its `expires` (`item_expired`) and a feed item whose `window` is not two numbers with the start before the end (`window_malformed`).

The reason shows on the video in the console, for example `media_encrypted`, `live_playlist`, `media_byterange`, `stream_host_not_allowed` or `media_too_large`. A few reasons can pass on their own (`stream_unreachable`, `copy_failed`, `metadata_unreadable`). Pick those videos again to retry.

## Long videos

The import handles event replays of 4 to 14 hours and several GB. A copy that stops halfway resumes where it stopped.

Transcription takes at most 10 hours of audio per file. For a longer replay, import one time range of it.

### Import one time range

You can import only part of a video, for example one day of a multi-day replay. In the console, set the range on the video before you pick it. With `import_catalog_items`, send `windows`: one `start_seconds` and `end_seconds` per picked video, in seconds of the video as your source plays it.

* The imported video is that range. Its times start at 0 at the range's start.
* HLS is cut on whole segments, so the range widens to the segment edges.
* A range can be at most `window_max_seconds` long. `get_catalog_source` returns that limit.
* A video your JSON Feed gives a `window` keeps the feed's range.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.