Skip to content

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.

  • One asset per row. The header row is required and must contain at least asset_type, ingest_id, and title.
  • Supported asset types in v1: MOVIE, EPISODE, SERIES, SEASON, PODCAST, SHORT, NEWS. CHANNEL, LIVE_EVENT, and EVENT are 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 same ingest_id updates the existing asset rather than creating a duplicate.
ColumnDescription
asset_typeOne of: MOVIE, EPISODE, SERIES, SEASON, PODCAST, SHORT, NEWS.
ingest_idYour stable external identifier for this asset. Used both for idempotent upserts and as the cross-row reference key for parents.
titleDisplay title.
ColumnDescription
descriptionLong-form description.
languageISO language code for title / description. Defaults to en.
production_yearInteger, e.g. 2024.
durationInteger, seconds.
age_ratingsPipe-separated list of age-rating codes, e.g. US_PG-13|DE_12.

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.

ColumnRequired forDescription
series_ingest_idSEASON, EPISODEingest_id of the parent series or podcast.
season_numberSEASON, EPISODEInteger. For an EPISODE, identifies the season within the series.
episode_numberEPISODEInteger.
ColumnRequired forDescription
source_urlMOVIE, EPISODE, NEWS, SHORTURL 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.

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.

ColumnDescription
genresPipe-separated list of genre names.
content_groupsPipe-separated list of static content group names. Dynamic content groups auto-populate via their own rules and are not assigned here.

One URL per column. Images are fetched asynchronously by the poster service after the import completes.

ColumnDescription
poster_swimlane_16x9_urlLandscape thumbnail used on swimlane rows.
poster_swimlane_2x3_urlPortrait thumbnail used on swimlane rows.
poster_details_16x9_urlLarge landscape hero image on the asset details screen.

The import runs in three passes so that cross-row references always resolve:

  1. ContainersSERIES / PODCAST are created first, then SEASON rows are attached to their series.
  2. Leaf assetsMOVIE / EPISODE / NEWS / SHORT rows are upserted. Each one also gets a transcoding (or pass-through for HLS/DASH) job enqueued.
  3. 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.

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_url
SERIES,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.jpg
SEASON,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.

The import always returns a per-row summary. Common skip reasons:

ReasonWhat it means
ingest_id is required / title is requiredA 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 importYou used CHANNEL, LIVE_EVENT, or EVENT — not supported yet.
MOVIE row requires source_urlA leaf row is missing its video source.
parent series with ingest_id '…' not foundThe 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):

WarningWhat it means
unknown genre '…' — skippedThe genre name doesn’t match anything in your tenant. Create the genre first, then re-upload.
unknown content_group '…' — skippedSame idea, for content groups.
Unknown columns ignoredThe CSV has columns that aren’t part of this schema. Safe to ignore, useful to catch typos.