CSV Import Schema
Upload a CSV on Media Catalog → Import → CSV File to create many assets in one go. Each row becomes one asset. Rows are validated individually: invalid rows are skipped and reported back to you, and the valid rows are imported.
At a glance
Section titled “At a glance”- One asset per row. The header row is required and must contain at least
asset_type,ingest_id, andtitle. - Supported asset types in v1:
MOVIE,EPISODE,SERIES,SEASON,PODCAST,SHORT,NEWS.CHANNEL,LIVE_EVENT, andEVENTare not supported yet. - Unknown columns are ignored (reported as warnings on the summary screen).
- List columns (
age_ratings,genres,content_groups) use|as the separator — e.g.Action|Drama. - Upserts by
ingest_id. Re-uploading a CSV with the sameingest_idupdates the existing asset rather than creating a duplicate.
Columns
Section titled “Columns”Required for every row
Section titled “Required for every row”| Column | Description |
|---|---|
asset_type | One of: MOVIE, EPISODE, SERIES, SEASON, PODCAST, SHORT, NEWS. |
ingest_id | Your stable external identifier for this asset. Used both for idempotent upserts and as the cross-row reference key for parents. |
title | Display title. |
Optional metadata
Section titled “Optional metadata”| Column | Description |
|---|---|
description | Long-form description. |
language | ISO language code for title / description. Defaults to en. |
production_year | Integer, e.g. 2024. |
duration | Integer, seconds. |
age_ratings | Pipe-separated list of age-rating codes, e.g. US_PG-13|DE_12. |
Parent linkage (for SEASON and EPISODE)
Section titled “Parent linkage (for SEASON and EPISODE)”Episodes and seasons reference their parent SERIES/PODCAST by ingest_id — either from
another row in the same CSV, or from an asset that already exists in your catalog.
| Column | Required for | Description |
|---|---|---|
series_ingest_id | SEASON, EPISODE | ingest_id of the parent series or podcast. |
season_number | SEASON, EPISODE | Integer. For an EPISODE, identifies the season within the series. |
episode_number | EPISODE | Integer. |
Video source
Section titled “Video source”| Column | Required for | Description |
|---|---|---|
source_url | MOVIE, EPISODE, NEWS, SHORT | URL to the video. Two kinds are accepted: a file URL (.mp4, .mov, etc.) kicks off the usual transcoding pipeline; an external manifest URL (.m3u8 for HLS or .mpd for DASH) is passed through without transcoding — the asset will play directly from your CDN. Detection is automatic based on the URL extension; no separate column is required. |
Taxonomy and curation
Section titled “Taxonomy and curation”Both taxonomy columns accept pipe-separated names (not UUIDs), matched case-sensitively against whatever you’ve configured in the admin panel. Unknown names produce a warning against the row but don’t fail the import — you can fix them up later in the admin panel.
| Column | Description |
|---|---|
genres | Pipe-separated list of genre names. |
content_groups | Pipe-separated list of static content group names. Dynamic content groups auto-populate via their own rules and are not assigned here. |
Posters
Section titled “Posters”One URL per column. Images are fetched asynchronously by the poster service after the import completes.
| Column | Description |
|---|---|
poster_swimlane_16x9_url | Landscape thumbnail used on swimlane rows. |
poster_swimlane_2x3_url | Portrait thumbnail used on swimlane rows. |
poster_details_16x9_url | Large landscape hero image on the asset details screen. |
Processing order
Section titled “Processing order”The import runs in three passes so that cross-row references always resolve:
- Containers —
SERIES/PODCASTare created first, thenSEASONrows are attached to their series. - Leaf assets —
MOVIE/EPISODE/NEWS/SHORTrows are upserted. Each one also gets a transcoding (or pass-through for HLS/DASH) job enqueued. - Taxonomy + posters — genres, content groups, and poster URLs are attached to every asset created in passes 1 and 2.
You don’t need to pre-sort your CSV — the import re-orders the rows internally.
Examples
Section titled “Examples”asset_type,ingest_id,title,description,language,production_year,duration,age_ratings,series_ingest_id,season_number,episode_number,source_url,genres,content_groups,poster_swimlane_16x9_url,poster_swimlane_2x3_url,poster_details_16x9_urlSERIES,bd,Breaking Drama,A gripping drama.,en,2024,,US_TV-14,,,,,Drama,Featured,https://cdn.example.com/bd-swim-16x9.jpg,https://cdn.example.com/bd-swim-2x3.jpg,https://cdn.example.com/bd-hero.jpgSEASON,bd-s1,Breaking Drama: Season 1,,en,,,,bd,1,,,,,,,EPISODE,bd-s1e1,Pilot,The one where it starts.,en,2024,2700,US_TV-14,bd,1,1,https://cdn.example.com/bd/s1e1.mp4,Drama,,,,EPISODE,bd-s1e2,Complications,,en,2024,2640,US_TV-14,bd,1,2,https://cdn.example.com/bd/s1e2.m3u8,Drama,,,,Row bd-s1e2 uses an HLS manifest — Vidori will play that back directly from your CDN
without transcoding. Row bd-s1e1 uses an MP4 file and will go through the normal
transcode pipeline.
asset_type,ingest_id,title,description,language,production_year,duration,age_ratings,series_ingest_id,season_number,episode_number,source_url,genres,content_groups,poster_swimlane_16x9_url,poster_swimlane_2x3_url,poster_details_16x9_urlMOVIE,mov-001,The Quiet Harbour,,en,2022,6420,,,,,https://cdn.example.com/quiet.mp4,Drama|Documentary,Featured,,,MOVIE,mov-002,Midnight in Lagos,,en,2023,5400,US_R,,,,https://cdn.example.com/midnight.mpd,Drama,Featured|New,,,MOVIE,mov-003,Hello Again,,en,2021,5760,US_PG,,,,https://cdn.example.com/hello.m3u8,Comedy,,,,Row mov-002 uses DASH (.mpd) and row mov-003 uses HLS (.m3u8); both skip
transcoding. Row mov-001 is a plain MP4 and runs the full transcode pipeline.
Error handling
Section titled “Error handling”The import always returns a per-row summary. Common skip reasons:
| Reason | What it means |
|---|---|
ingest_id is required / title is required | A required column is empty on that row. |
unknown asset_type '…' | The value in asset_type doesn’t match any supported type. |
asset_type '…' is not supported in v1 CSV import | You used CHANNEL, LIVE_EVENT, or EVENT — not supported yet. |
MOVIE row requires source_url | A leaf row is missing its video source. |
parent series with ingest_id '…' not found | The series an EPISODE/SEASON points to isn’t in the CSV or the catalog. |
duplicate ingest_id '…' | Two rows in the same CSV share an ingest_id. Only the first is kept. |
Warnings (import succeeds, but something was not applied):
| Warning | What it means |
|---|---|
unknown genre '…' — skipped | The genre name doesn’t match anything in your tenant. Create the genre first, then re-upload. |
unknown content_group '…' — skipped | Same idea, for content groups. |
Unknown columns ignored | The CSV has columns that aren’t part of this schema. Safe to ignore, useful to catch typos. |