Videobana

JSON format

Everything a video document can contain. This page is generated from the same schema the engine validates with, so it is always exact.

The document at a glance

A video is one JSON object. Only title and scenes are required; the look comes from the domain, the voice from sensible defaults. This example uses every part of the envelope:

{
  "version": 1,
  "title": "Coffee, Explained",
  "subtitle": "How a bean becomes your morning cup.",
  "topic": "How coffee is made",
  "domain": "food",
  "emoji": "โ˜•",
  "kicker": "Kitchen science ยท Episode 1",
  "chips": [
    "Beginner",
    "2 minutes"
  ],
  "brand": {
    "name": "Daily Bites",
    "tagline": "Learn something tasty"
  },
  "style": {
    "palette": "ember",
    "fonts": "editorial",
    "background": "food",
    "mascot": "buddy",
    "enter": "slide-up",
    "transition": "fade",
    "shape": "soft",
    "captions": "plain"
  },
  "narration": {
    "voice": "F1",
    "speed": 0.95,
    "lang": "en",
    "pauses": {
      "section": 1.8
    },
    "pronunciations": {
      "espresso": "ess-PRESS-oh"
    }
  },
  "followUps": [
    {
      "kicker": "Try this",
      "title": "Brew a cup with a method you have never used",
      "tone": "amber"
    }
  ],
  "scenes": [
    {
      "kind": "intro",
      "say": [
        "Welcome to Daily Bites.",
        "Today we follow a coffee bean from the farm to your cup."
      ]
    },
    {
      "kind": "cards",
      "heading": "From bean to cup",
      "layout": "flow",
      "lead": "Every cup of coffee goes through four steps.",
      "items": [
        {
          "icon": "๐ŸŒฑ",
          "title": "Grow",
          "text": "Coffee cherries ripen on the tree.",
          "say": "First, coffee cherries ripen on the tree."
        },
        {
          "icon": "๐Ÿ”ฅ",
          "title": "Roast",
          "text": "Heat turns green beans brown.",
          "tone": "orange",
          "say": "Then roasting turns the green beans brown and brings out the flavour."
        },
        {
          "icon": "โš™๏ธ",
          "title": "Grind",
          "text": "Smaller pieces extract faster.",
          "say": "Grinding breaks the beans into small pieces so water can reach the flavour."
        },
        {
          "icon": "โ˜•",
          "title": "Brew",
          "text": "Hot water carries the flavour.",
          "tone": "amber",
          "say": "Finally, hot water carries that flavour into your cup."
        }
      ],
      "outro": "Change any step, and the taste changes too."
    },
    {
      "kind": "statement",
      "eyebrow": "Remember",
      "text": "The **grind size** matters more than most people think.",
      "icon": "๐Ÿ’ก",
      "say": "The grind size matters more than most people think."
    }
  ]
}
  • title โ€ฆ followUps describe the video as a whole: the title card, the top bar and the recap.
  • style chooses colours, fonts, backgrounds, host, animations and captions. Leave a field out and the domain decides.
  • narration chooses the voice and the pauses.
  • sound adds sound design made for the video: whooshes, hits, risers and an optional music bed.
  • scenes is the story: a list of scenes played in order (scene reference).

Video fields

FieldTypeWhat it does
version1

Spec format version. Always 1.

titlerequiredstring

Shown in the top bar and on the title card.

Limits: 1โ€“80 characters

subtitlestring

One-sentence summary, shown on the title card.

Limits: 1โ€“220 characters

topicstring

What the video is about. Used to pick a look when domain is not set.

Limits: 1โ€“200 characters

domainenum

Topic area. Picks a matching default look; anything in style overrides it.

generalfinancebusinessmarketingtechnologyaicybersecurityeducationsciencekidshealthfitnessfoodtravelnaturehistorynewsgamingrealestatesportslegallifestyleartspacecareerenvironmentautomotivemusiccelebrationmindfulnessmysterypets

aspectenum

The shape the video is made for: 16:9 (default) for screens, 9:16 for Shorts, Reels and TikTok, 1:1 or 4:5 for feeds. The editor, the watch page and the export start from it. Wide shapes use the landscape layout, the others the phone layout.

16:94:31:14:53:49:16

emojistring

Shown beside the host on the title card.

Limits: 1โ€“8 characters

kickerstring

Small line above the title in the top bar, e.g. Lesson 3 ยท Core skills.

Limits: 1โ€“48 characters

chipsstring[]

Pills above the title on the title card.

Limits: 0โ€“4 items, each 1โ€“24 characters

brandobject
โ”” namestring

Shown in the top bar (and on the end card).

Limits: 1โ€“32 characters

โ”” taglinestring

Limits: 1โ€“60 characters

โ”” logostring

Address of your logo (PNG, SVG or JPEG with an http(s) address, a data:image URL or a path starting with /). Shown in a corner of every scene.

โ”” logoPositionenum

Which corner the logo sits in. Default top-right.

top-righttop-leftbottom-rightbottom-left

โ”” logoPlateenum

A rounded plate behind the logo, for a logo that would not stand out on the video's background: light for a dark logo, dark for a light one. Default: none.

lightdark

hostobject

A picture of the presenter, shown instead of the drawn mascot (in the top bar and on the title card).

โ”” srcrequiredstring

Address of the picture of the host: a cut-out with a transparent background works best.

โ”” altstring

Who or what the host is.

Limits: 1โ€“150 characters

โ”” promptstring

What the AI was asked to paint. Kept so the picture can be made again; it is not shown.

Limits: 1โ€“600 characters

musicobject
โ”” srcrequiredstring

Address of the music: an http(s) link to an MP3, WAV, M4A or OGG file, or an uploaded one (/api/assets/<id>). It loops to fill the video and fades out at the end.

Limits: up to 2000 characters

โ”” namestring

The name of the file, shown in the editor.

Limits: 1โ€“120 characters

โ”” volumenumber

Loudness of the music, 0 to 1, where the narration is 1. Default 0.18.

Limits: 0โ€“1

โ”” duckboolean

Lower the music further while the narrator speaks. Default true.

audioobject[]

Recordings and music placed on the timeline, each playing part of an uploaded file from a given second of the video. Exports mix them in (mp4, webm, mov, mp3).

Limits: up to 24 items

โ”” kindrequiredenum

voice: a recording, as loud as the narrator. music: lowered under the narrator.

voicemusic

โ”” srcrequiredstring

Address of the uploaded audio (/api/assets/<id>).

โ”” namestring

The name of the file, shown in the editor.

Limits: 1โ€“120 characters

โ”” durationrequirednumber

Length of the whole file in seconds.

Limits: 0.2โ€“3600

โ”” startrequirednumber

Where the clip begins, in seconds from the start of the video.

Limits: 0โ€“3600

โ”” offsetnumber

Seconds cut from the beginning of the file. Default 0.

Limits: 0โ€“3600

โ”” lengthrequirednumber

Seconds of the file that play, from offset.

Limits: 0.2โ€“3600

followUpsobject[]

Cards beside the recap: a hands-on task, what to watch next.

Limits: 0โ€“3 items

โ”” kickerrequiredstring

Limits: 1โ€“24 characters

โ”” titlerequiredstring

Limits: 1โ€“48 characters

โ”” toneenum

Accent colour. rose marks a negative item (cross), emerald a positive one.

violetemeraldamberroseskyfuchsiatealorange

scenesrequiredobject[]

Limits: 1โ€“40 items

style: the look

Every field is optional and {} is a complete style. Precedence, highest first: what you write in style, then the profile of the domain, then the default. Every palette, font, background and animation is shown on Looks & styles.

FieldTypeWhat it does
styleobject
โ”” themeenum

A complete ready-made look (palette, fonts, background, motion, captions, effects) in one word. Every other style field overrides it.

neon-nightspaper-presskids-funboardroomarcadeocean-calmgolden-hourmidnight-technewsroomchalkboard-classblueprint-labcinemasunny-popforest-walkcotton-candyminimal-inkgalaxy-questretro-tvterracotta-studiovolcanicspringtimegold-luxeshowroomlaunch-nightflash-salefresh-glowapp-glasssaas-lightorganic-marketkitchen-tablebold-streetclinic-calmfintech-proestate-classicfestival-popsunset-escapeedu-bright

โ”” paletteenum

Colour scheme: a list of backdrops the scenes cycle through. See the palette catalog.

classicvioletoceanemeraldsunsetberrymidnightgraphitecorporateroyalneonemberforestmatrixpaperarcticmintlavenderpeachcandynoircherrycoppergalaxyskysagesandblushauroratwilightvolcanodeepseagoldjadecreamlemoncoralmeadowporcelainterracottasunrise

โ”” brandColorstring

Builds a palette around this colour. Wins over palette.

Limits: hex colour such as #7c3aed

โ”” modeenum

dark or light. Chooses a palette of that mode when none is named.

darklight

โ”” textColorstring

Text colour. Defaults to white (dark) or deep ink (light). Replaced if it would be unreadable.

Limits: hex colour such as #7c3aed

โ”” accent[string, string]

The two highlight colours: title gradient, spoken caption word, brand name.

Limits: exactly 2 items, each hex colour such as #7c3aed

โ”” cycleBackdropsboolean

true (default): each scene moves to the next backdrop. false: one backdrop throughout.

โ”” tonesenum

Accent set for chips, bars and chart parts.

vividpastelmutedmononeonearthcandyoceanretro

โ”” fontsenum

Heading and body font pairing.

classicmodernfriendlycorporatetechnicalterminaleditorialboldplayfulsportyhandwrittensturdystartupreadablemagazineposterbubblymarkersurfbookretro-techfriendly-sans

โ”” displayFontenum

Overrides the heading font of the pairing.

geistinterdm-sansmanropepoppinsplus-jakarta-sansspace-grotesknunitobaloo-2playfair-displayloraroboto-slaboswaldbricolage-grotesquecaveatjetbrains-monooutfitsoralexendrubikfredokamerriweatherdm-serif-displaybebas-neuepacificopermanent-markerspace-mono

โ”” bodyFontenum

Overrides the body font of the pairing.

geistinterdm-sansmanropepoppinsplus-jakarta-sansspace-grotesknunitobaloo-2playfair-displayloraroboto-slaboswaldbricolage-grotesquecaveatjetbrains-monooutfitsoralexendrubikfredokamerriweatherdm-serif-displaybebas-neuepacificopermanent-markerspace-mono

โ”” backgroundenum

A ready-made stack of animated background layers.

generalfinancebusinessmarketingtechnologyaicybersecurityeducationsciencekidshealthfitnessfoodtravelnaturehistorynewsgamingrealestatesportslegallifestyleartminimalcalmdreamycosmoschalkboardsnowyneoncyberpunkoceansunsetautumnstormspacehyperspaceblueprintnotebookretropartycelebrationforestnightwarmpoplowpolymusicradarbiotechindustrialsilkmaplavastagelabgeneticsdeveloperspringtimecarnivalfireworksmysterystudiomarketsisometricplaygroundmeditationhypnoticliquidarcadeskiespapershowroomlaunchflashglasssaasfreshmarketkitchenstreetwellnessfintechestatefestivalescapeschoolnone

โ”” backgroundLayersenum[]

Your own stack of layers, bottom to top. Wins over background. [] for a plain backdrop.

Limits: up to 6 items

blobsgridchart-wavefloatersstarsaurorawavesdotsdiagonalhexbokehbubblesparticlesmatrixnetworkcircuitraysmountainsskylinegrainspotlightpaperchalkconfettisnowcloudsstreamsperspectivemeshlavaribbonssuntopoblueprintnotebookgearswaveformwarpgalaxyorbitscometssparklesradarfirefliesrainembersleavesunderwaterlightninglanternshalftonetrianglesshapesequalizerscanlinesripplesspiralbeamsflowpixelsdnaatomsformulascodebirdsballoonsfireworkspetalsfogfilmstriptickerisogriddoodlessoftboxlightsweeporbsspeedlinesaura

โ”” glyphsstring[]

Symbols or emoji for the floaters background.

Limits: 1โ€“12 items, each 1โ€“4 characters

โ”” mascotenum

The host character.

candlebuddyrobotowlcatfoxbearnone

โ”” enterenum

How items appear.

popfadeslide-upslide-leftslide-rightslide-blurdriftzoomfocus-pullblurfliptiltrotateswingbouncedropelasticgrowlaunchrevealreveal-upcurtainiriswarp-inflashglitchnone

โ”” transitionenum

How scenes replace each other.

risefadeslide-leftslide-rightslide-upslide-downzoom-inzoom-outblurblur-zoomwhipflipcubewipewipe-upirisdiamondsplit-hswirldropbounceelasticthroughburndipflashglitchtvnone

โ”” shapeenum

Corner roundness of cards and chips.

sharpsoftroundpillbubble

โ”” captionsenum

Caption look.

glassplainhighlightoutlinebarboldneonstickerunderlineboxedkaraokecinemacomicgradientterminal

โ”” captionPositionenum

Where captions sit.

bottomtop

โ”” progressenum

A progress indicator along the top edge. Default: none. A scene can hide or show it for itself with its own progress.

nonebardotsglowring

โ”” headerenum[]

Which parts of the top bar show on every scene except the title card: host, title, kicker, brand. Default: all four. [] removes the bar. A scene can hide or show the bar for itself with its own header.

Limits: up to 4 items

hosttitlekickerbrand

โ”” cameraenum

drift (default): the picture moves slowly all the time, like a camera. dolly: a clearer move that lasts as long as each scene (best for ads). handheld: a faint human sway. still: it does not move.

driftdollyhandheldstill

โ”” gradeenum

A colour grade over the whole picture, like the last step of a professional edit: clean, cinematic (teal and orange), warm, cool, punchy, matte or luxe. Default: none.

cleancinematicwarmcoolpunchymatteluxe

โ”” safeZoneenum

For a tall video (9:16) made for a social platform: keeps the titles, captions and logo clear of the parts of the screen the app covers. Default: none.

tiktokreelsshortsall

โ”” effectsenum[]

Finishing touches over the whole picture (vignette, letterbox, film, glow ...). Combine up to four. [] for none.

Limits: up to 4 items

vignetteletterboxframefilmmonovividdimleakhazeglowchromaticscanfxshinegrain

narration: the voice

engine is standard (the default): the voices, speed and languages of the Supertonic text-to-speech server. Press play to hear each voice (the samples are in English; every voice speaks all the languages). Or it is premium: Google Gemini 3.8 Flash TTS, directed with premium and the delivery of every scene. Pauses are in seconds.

  • Male voice 1
  • Male voice 2
  • Male voice 3
  • Male voice 4
  • Male voice 5
  • Female voice 1
  • Female voice 2
  • Female voice 3
  • Female voice 4
  • Female voice 5

The 30 premium voices, each with the quality Google gives it:

  • Zephyr ยท Bright
  • Puck ยท Upbeat
  • Charon ยท Informative
  • Kore ยท Firm
  • Fenrir ยท Excitable
  • Leda ยท Youthful
  • Orus ยท Firm
  • Aoede ยท Breezy
  • Callirrhoe ยท Easy-going
  • Autonoe ยท Bright
  • Enceladus ยท Breathy
  • Iapetus ยท Clear
  • Umbriel ยท Easy-going
  • Algieba ยท Smooth
  • Despina ยท Smooth
  • Erinome ยท Clear
  • Algenib ยท Gravelly
  • Rasalgethi ยท Informative
  • Laomedeia ยท Upbeat
  • Achernar ยท Soft
  • Alnilam ยท Firm
  • Schedar ยท Even
  • Gacrux ยท Mature
  • Pulcherrima ยท Forward
  • Achird ยท Friendly
  • Zubenelgenubi ยท Casual
  • Vindemiatrix ยท Gentle
  • Sadachbia ยท Lively
  • Sadaltager ยท Knowledgeable
  • Sulafat ยท Warm
FieldTypeWhat it does
narrationobject
โ”” engineenum

standard (default): the voice server, with voice, speed and quality. premium: Google Gemini 3.8 Flash TTS through OpenRouter, directed with premium and the scenes' delivery.

standardpremium

โ”” premiumobject

The premium voice: which of the 30 voices, how it delivers the video, accent and pace. Only used when engine is premium.

โ”” voiceenum

One of 30 studio voices (see GET /api/catalog). Default Kore.

ZephyrPuckCharonKoreFenrirLedaOrusAoedeCallirrhoeAutonoeEnceladusIapetusUmbrielAlgiebaDespinaErinomeAlgenibRasalgethiLaomedeiaAchernarAlnilamSchedarGacruxPulcherrimaAchirdZubenelgenubiVindemiatrixSadachbiaSadaltagerSulafat

โ”” stylestring

How the whole video is delivered: emotion, energy, inflection. Short and concrete, e.g. "warm, confident, with a smile in the voice". Scenes can add to it with their own delivery.

Limits: 1โ€“160 characters

โ”” accentstring

A regional accent or dialect as a soft hint, e.g. "British" or "Scottish". The voice keeps its own character; the model follows the hint most of the time.

Limits: 1โ€“40 characters

โ”” paceenum

How quickly the voice speaks. Default natural.

slownaturalbrisk

โ”” voiceenum

Standard voice id. M1-M5 male, F1-F5 female. Default F2.

M1M2M3M4M5F1F2F3F4F5

โ”” speednumber

Standard voice: 1 = normal speech. Default 0.95.

Limits: 0.5โ€“2

โ”” qualityenum

Standard voice: more synthesis steps sound better and take longer. Default medium.

lowmediumhigh

โ”” langenum

Language of the narration. Default en. zh, th, he, ms, no have no voice: the video is silent, with captions, unless you add your own voiceover.

enkojaarbgcsdadeelesetfifrhihrhuiditltlvnlplptroruskslsvtrukvizhthhemsnona

โ”” silentboolean

true skips the voice entirely: timing is estimated from the text length and captions carry the video.

โ”” voiceoverobject

Your own recording instead of the generated voice. The captions and the scenes follow it. Ignored when silent is true.

โ”” srcrequiredstring

Address of the uploaded audio (/api/assets/<id>). Upload it in the editor, or with POST /api/assets.

โ”” durationrequirednumber

Length of the audio in seconds. The scenes are spread over it in proportion to what they say.

Limits: 0.5โ€“3600

โ”” namestring

The name of the file, shown in the editor.

Limits: 1โ€“120 characters

โ”” pausesobject
โ”” sentencenumber

Seconds of silence after each sentence.

Limits: 0โ€“10

โ”” sectionnumber

Seconds of silence between scenes.

Limits: 0โ€“10

โ”” leadInnumber

Seconds of silence before the first word.

Limits: 0โ€“10

โ”” tailnumber

Seconds of silence after the last word.

Limits: 0โ€“10

โ”” pronunciationsmap<string, string>

Respellings for words the voice mispronounces, e.g. { "Kubernetes": "koo-ber-NET-eez" }. Captions keep the original spelling.

โ”” foreignmap<string, string[]>

Names, words and phrases that belong to another language than the narration, spoken by that language's voice in the middle of the sentence, e.g. { "de": ["Brandenburger Tor", "Kreuzberg"] } in an English video. Whole words only, spelled as in the narration; the captions are not changed.

sound: the sound design

Sound effects and a music bed made for the video, from nothing: no files are needed. Whooshes ride the cuts, a riser and an impact land as the product appears, and the bed's tempo is fitted to the cuts so they fall on the beat. The narrator is always on top, and the whole mix is mastered to about โˆ’15 LUFS. Left out, the video has none.

FieldTypeWhat it does
soundobject

Sound design made for the video itself: whooshes on the cuts, a riser and an impact into the reveal, small pops for text, and an optional music bed whose tempo is fitted to the cuts. Exports mix it in (mp4, webm, mov). Left out, the video has none.

โ”” effectsenum

How lively the sound effects are: off, soft, punchy (default) or cinematic. Whooshes on the cuts, risers and impacts into the reveal, small pops for text and a sparkle on the offer. Made from nothing, so no files are needed.

offsoftpunchycinematic

โ”” bedenum

A music bed made to the cuts of the video, so they land on the beat: ambient, pulse or drive. Default off. For your own track use music.

ambientpulsedriveoff

โ”” bedVolumenumber

How loud the bed is under the narrator, 0 to 1. Default 0.4.

Limits: 0โ€“1

โ”” effectsVolumenumber

How loud the sound effects are, 0 to 1, where the narrator is 1. Default 0.6.

Limits: 0โ€“1

How narration drives the picture

Every scene has narration (say), and the narration decides when things appear. The sentences are spoken in order, and each one reveals more of the scene: an item appears just before the sentence that talks about it. So you never time anything by hand; you only write what the narrator says.

Take this cards scene:

{
  "kind": "cards",
  "heading": "Three states of water",
  "lead": "Water exists in three states.",
  "items": [
    {
      "title": "Ice",
      "text": "Solid below zero.",
      "say": "Below zero it freezes into ice."
    },
    {
      "title": "Liquid",
      "text": "What we drink.",
      "say": "In between it is a liquid."
    }
  ],
  "outro": "Heat decides which one you get."
}
Narrator saysWhat is on screen
leadThe heading only
items[0].sayโ€ฆand the Ice card
items[1].sayโ€ฆand the Liquid card
outroBoth cards stay while the last sentence is spoken

Each scene kind has its own mapping, described under its name in the scene reference. A say with several sentences is split at the full stops; each sentence is a separate clip, so keep them short.

Narration is plain text. Do not put markup or emoji in say; the captions would show it. Digits and symbols are read out in English; in other languages, write numbers in words. The one exception is the premium voice, which performs a few tags (such as <breath> or <sigh>) written in the sentence: the captions leave them out.

Pictures on a scene

Every scene may carry an image: a picture behind it or beside its content. The editor makes them with the AI (Pictures tab), but any address works, so you can use your own.

modeWhat it does
backdropFills the frame behind the scene, softened and darkened so the text stays easy to read. The default.
cutoutA picture with a transparent background that floats beside the content, on the side you choose (right by default).
cardA framed photo, slightly tilted, beside the content, on the same side. It works with any picture.

motion makes the picture move while its scene is on screen. A backdrop takes zoom-in, zoom-out, pan or still; a cut-out or card takes float (the default), sway, spin, turn, pulse, bounce or still. A scene without motion uses the default of its mode.

{
  "kind": "statement",
  "text": "Sunlight is made of **every colour** at once.",
  "say": "Sunlight is made of every colour at once.",
  "image": {
    "src": "/api/assets/3c9d0e5a71b2f486",
    "alt": "A prism splitting white light",
    "mode": "backdrop"
  }
}

src is the address of a picture of yours (/api/assets/<id>) or an http(s) link. prompt keeps what the AI was asked to paint, so the picture can be made again; it is never shown. Pictures are drawn in exports too. A media scene shows a picture of its own, full size, instead. A gallery scene shows several pictures that move, as a mosaic, a stack, a carousel or a flipbook. The presenter can be a picture too: host (src and alt, a cut-out works best) replaces the drawn mascot.

Paint them from code with POST /api/images: the AI paints up to 25 pictures (cut-outs, cards, backdrops and the host together) on one sprite sheet in one call, and every picture that comes out counts as one image credit.

Rich text on screen

Text shown on screen (headings, card titles, statements, table cellsโ€ฆ) supports three marks and nothing else, on purpose:

WriteYou get
**compound interest**compound interest
`git commit`git commit
==less code==less code

Limits

Limits keep text inside its box, even on a vertical video. Going over a limit is an error that says which field and by how much.

LimitValue
Scenes in one video40
Characters of the video title80
Characters of a scene heading60
Characters of a card, step or row title48
Characters of a card or step description150
Characters of one table cell48
Characters of one narration line (say)500
Characters of a big number such as +27%14
Items (cards, steps, rowsโ€ฆ) in one scene8
Lines of a code scene12
Characters of one code line64
Chips on the title card4
Bullets in the recap of an outro6

Validation: errors and warnings

A document is checked in three steps. Structure: right fields, right types, within the limits. Meaning: things that are valid JSON but make no sense (a quiz whose answer is not one of its options, a funnel that grows). Quality: advice that never blocks you (no title card, a very long sentence, five identical scenes in a row).

Errors stop a video from being saved; warnings do not. Every issue has a path to the field and often a hint. This is what POST /api/validate answers for a document with two mistakes:

{
  "valid": false,
  "errors": [
    {
      "level": "error",
      "path": "scenes[0].items[0].icon",
      "message": "Required field is missing."
    },
    {
      "level": "error",
      "path": "scenes[0].items[0].say",
      "message": "Required field is missing."
    },
    {
      "level": "error",
      "path": "scenes[1].kind",
      "message": "Unknown scene kind \"fireworks\".",
      "hint": "Did you mean \"forecast\" or \"reviews\" or \"timer\"? Allowed: intro, section, statement, cards, table, example, stat, chart, ranking, versus, feature, timeline, cycle, funnel, ... (92 in total, see the docs)."
    }
  ],
  "warnings": [],
  "stats": null
}

JSON Schema

The complete JSON Schema (draft 2020-12) is available at GET /api/schema. Point your editor at it for completion and inline errors, or validate documents in your own pipeline before sending them. In VS Code, map it in .vscode/settings.json:

{
  "json.schemas": [
    {
      "fileMatch": [
        "*.video.json"
      ],
      "url": "http://localhost:3300/api/schema"
    }
  ]
}

Using documents in your own code

  • Keep the document in version control as plain JSON; a video can always be made again from it.
  • Unknown fields are rejected: a typo such as pallete is an error, not silently ignored.
  • Send documents as { "spec": { โ€ฆ } } to the API (see HTTP API).