Core concepts

Five objects underlie everything in Motionpit. Once you understand how they relate, the API surface is obvious.


Format

A format is the template — the full video definition. It holds:

  • An ordered op list (the timeline): a sequence of block ops and transition ops.
  • A brand kit reference (logo, colors, music).
  • A parameter binding table: the named API variables the format exposes and where in the op list each one writes.
  • A default override map: the author-set fallback values for every binding.

Formats are identified by a URL-safe slug derived from the format's name (e.g. daily-sports-recap). All render API calls use the slug, not an internal ID.

A format has a status of draft or published. Only published formats can accept render requests from API-key callers.


Block

A block is one segment of a format's timeline — a single rendered scene. There are two categories:

Built-in blocks are provided by the platform. They have fixed structure and a defined set of parameterizable fields:

| Block kind | Parameterizable fields | |---|---| | titleCard | headline, subheadline | | quote | text, attribution | | keyValue | label, value, caption | | photo | caption | | logoReveal | tagline | | endCard | handle, tagline, website | | outroCTA | headline, cta, ctaUrl | | countdown | targetAt, labelPrefix, expiredText | | labeledList | title | | statGrid | title |

User blocks are custom canvas layouts your team authors at /user-blocks/new. A user block contains one or more cells — positioned elements (text, stat, image, data table, etc.) — whose fields can be parameterized individually.

Transition ops (cuts, fades) sit between blocks on the timeline. They cannot be parameterized — they have no content surface.


Parameter and binding

A parameter is a named, typed variable that an API caller can supply to change a specific field in a specific block. Parameters have:

  • A public name — the dotted string callers use in variables (e.g. game1.player.name).
  • A type — one of text, number, currency, percent, image, color, or table.
  • A default value — the value used when the caller omits the variable.
  • A required flag — when true, the render API returns 422 missing_required_variable if the caller doesn't supply it.
  • A deprecated flag — set automatically when the target field is deleted or renamed; callers sending deprecated names still render but see a warning.

A binding is the server-side record that links a public name to the exact JSON path inside the op list where the value should land. Bindings are managed automatically by the format editor — authors never write JSON Pointers directly.


Instance label

When a block (built-in or user block) is dropped onto a format timeline, it gets an instance label — a short identifier like game1 or titleCard-1. The instance label is a prefix that namespaces the block's parameters within the format.

Example: a user block with a player.name parameter, dropped as instance game1, exposes game1.player.name in the render API. If you drop the same block twice as game1 and game2, callers supply game1.player.name and game2.player.name independently.

Built-in blocks get synthetic labels like titleCard-1, quote-2. Authors can rename them in the timeline editor.


Render job

A render job is a queued request to produce an MP4 from a format with a specific set of variable values. Jobs are asynchronous: the API returns a job id immediately, and you poll GET /v1/renders/:id for status.

Possible statuses: queuedrenderingcompleted or failed.

Once completed, call GET /v1/renders/:id/signed-url to fetch a presigned download URL (valid 24 hours). Alternatively, configure webhooks to receive a push event instead of polling.

A failed job is terminal — create a new render rather than retrying the same job ID.


How they fit together

Format
  └── Op list
        ├── Block op (titleCard-1)    ← has bindings
        │     binding: "titleCard-1.headline" → /ops/0/content/headline
        ├── Transition op (cut)       ← no bindings possible
        ├── Block op (game1)          ← user block, has bindings
        │     binding: "game1.player.name" → /ops/2/content/cells/abc.../content/text
        └── Block op (endCard-1)      ← has bindings
              binding: "endCard-1.handle" → /ops/3/content/handle

POST /v1/formats/daily-sports-recap/renders
  { "variables": { "game1.player.name": "LeBron James", "titleCard-1.headline": "Tonight's Recap" } }
         ↓
  Render job (id: rj_01...)
         ↓
  GET /v1/renders/rj_01.../signed-url → presigned MP4 URL

See the Quickstart for a working end-to-end example.