Parameters in depth
Parameters are the bridge between your data and a rendered video. This page covers the full lifecycle: how parameters are created, how to discover them, how to supply values, and how type coercion works.
How parameters are created
Parameters are created automatically when an author edits a block field in the format editor. The flow:
- Author drops any block (built-in or custom user block) onto the format timeline.
- Author edits a field — e.g. changes the headline text on a
titleCardblock. - The editor auto-creates a named parameter binding for that field:
titleCard-1.headline. - The binding appears in the API Parameters tab of the format editor with the edited value as the default.
Authors can also create parameters explicitly via the gear icon next to any field in the inspector panel, which opens a "Mark as parameter" dialog to set a custom name.
Transitions cannot be parameterized. Transition ops (cuts, fades) have no content surface and are always omitted from the binding table.
Discover a format's schema
Before you write a render call, fetch the current parameter contract:
curl "$BASE/formats/daily-sports-recap/schema" \
-H "Authorization: Bearer $API_KEY"
Response:
{
"slug": "daily-sports-recap",
"version": 1745276400000,
"durationFrames": 450,
"variables": [
{
"name": "titleCard-1.headline",
"type": "text",
"required": false,
"defaultValue": "Tonight's Recap",
"sourceBlock": "titleCard",
"deprecated": false
},
{
"name": "game1.player.name",
"type": "text",
"required": false,
"defaultValue": "Player Name",
"sourceBlock": "sports-recap",
"deprecated": false
},
{
"name": "game1.team.score",
"type": "number",
"required": false,
"defaultValue": 0,
"sourceBlock": "sports-recap",
"deprecated": false
}
],
"exampleBody": {
"variables": {
"titleCard-1.headline": "Tonight's Recap",
"game1.player.name": "Player Name",
"game1.team.score": 0
}
}
}
Key fields:
| Field | Meaning |
|---|---|
| name | The dotted string to use as the key in variables |
| type | Value type — see coercion rules below |
| required | When true, the render API returns 422 if the caller omits the variable |
| defaultValue | Value used when the caller omits the variable (only present when required: false) |
| sourceBlock | The block kind or user-block slug the parameter belongs to |
| deprecated | true when the target field was deleted or renamed; the variable still renders but should be removed from integrations |
Re-fetch this endpoint whenever you see 422 unknown_variable or after an author updates the format — the version field (Unix milliseconds) increments on every format save and can be used to detect staleness.
Supplying variables in a render request
Pass variables as a flat object keyed by parameter name:
curl -X POST "$BASE/formats/daily-sports-recap/renders" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"variables": {
"titleCard-1.headline": "Final: Lakers 112 – Warriors 108",
"game1.player.name": "LeBron James",
"game1.team.score": 112
}
}'
You only need to send variables whose values differ from the defaults. Variables you omit fall back to the defaultValue set by the author. If the author didn't set a default and the parameter is required: true, the API returns 422 missing_required_variable.
Instance-label scoping and the bare-name shortcut
Every parameter name is prefixed by the block's instance label (e.g. game1.). If your format has exactly one instance that exposes a given bare name, you can omit the prefix:
{ "variables": { "player.name": "LeBron James" } }
is equivalent to:
{ "variables": { "game1.player.name": "LeBron James" } }
when game1 is the only instance that has a player.name binding. If two instances share the same bare name, the API returns 422 variable_ambiguous with the scoped alternatives in details.fields.
Type coercion rules
The platform applies lenient coercion before writing values. The rules per type:
| Type | Accepted inputs | Rejected inputs |
|---|---|---|
| text | any scalar (string, number, boolean) — all coerced to String() | null, objects, arrays |
| number | number literals; numeric strings (e.g. "112") | non-numeric strings, null, objects |
| currency | same as number | same |
| percent | same as number | same |
| image | string (DigitalOcean Spaces key, e.g. "uploads/org-abc/photo.jpg") | non-strings |
| color | LayoutColorRef object or a hex string (e.g. "#ff0000") or a brand token string | anything unparseable by LayoutColorRef |
| table | array of row tuples — each row is (string \| number \| null)[] — max 50 rows | non-arrays, rows with non-scalar cells, > 50 rows |
Coercion happens field-by-field. If any variable fails, the entire render request is rejected with 422 invalid_variable_type before a render job is queued (no quota consumed).
color type detail. A color value is a LayoutColorRef, which can be:
- A hex string:
"#1a2b3c" - A brand token:
"brand.primary"(resolves against the format's brand kit at render time) - A full
LayoutColorRefobject:{ "hex": "#1a2b3c" }or{ "brandToken": "brand.primary" }
table type detail. A table value replaces the entire rows array of a data table cell. Each row is a positional tuple of values matching the cell's column definitions. Example:
{
"variables": {
"game1.stats": [
["Points", 112, "108"],
["Rebounds", 45, 38],
["Assists", 27, 22]
]
}
}
Which block fields can be parameterized
Not all fields on a block are parameterizable. The platform tracks a compatibility map per cell type:
User-block cell types:
| Cell type | Parameterizable fields |
|---|---|
| text | content.text (type: text), style.color (type: color) |
| bigNumber | content.value (number/currency/percent), content.label (text), style.valueColor (color), style.labelColor (color) |
| stat | content.label (text), content.value (text/number/currency/percent), style.color (color) |
| image | content.spacesKey (image) |
| rectangle | style.fill (color), style.borderColor (color) |
| dataTable | content.rows (table), style.headerColor (color), style.bodyColor (color), style.accentColor (color), style.rowBackgroundColor (color), style.dividerColor (color) |
| logo, circle, line, icon, gradient | Not parameterizable in v1 |
Built-in block kinds:
| Block kind | Parameterizable fields |
|---|---|
| titleCard | headline (text), subheadline (text) |
| photo | imageUrl (text), caption (text) |
| quote | text (text), attribution (text) |
| keyValue | label (text), value (text/number/currency/percent), caption (text) |
| logoReveal | tagline (text) |
| endCard | handle (text), website (text), tagline (text) |
| outroCTA | headline (text), cta (text), ctaUrl (text) |
| countdown | targetAt (text — ISO-8601 string), labelPrefix (text), expiredText (text) |
| labeledList | title (text) |
| statGrid | title (text) |
Attempting to bind a field that is not in the compatibility map returns 422 unsupported_parameter_field.
Deprecated parameters
When an author edits a block after parameters have been created — deleting a cell, renaming a cell's label — the affected bindings are marked deprecated: true in the schema response. Deprecated bindings still work (the render resolves them) but you should update your integration:
- Re-fetch
GET /v1/formats/:slug/schema. - Remove any variable keys whose entry has
"deprecated": true. - If the field was renamed, add the new name.
Sends that reference deprecated names do not cause errors, but the platform emits a warning in the render log.
422 error reference for variables
| Code | Meaning | Fix |
|---|---|---|
| unknown_variable | Variable name not in format's binding table | Re-fetch /schema for current names |
| variable_ambiguous | Bare name matches multiple instances | Use scoped name (e.g. game1.player.name) |
| missing_required_variable | Required variable omitted with no default | Add the variable, or set a default in the format editor |
| invalid_variable_type | Value fails type coercion | Check type in /schema, fix the value |
| parameter_path_stale | Binding points at a cell field that no longer exists | Re-mark the parameter in the block designer |
| variables_and_overrides_exclusive | Both variables and contentOverrides in body | Use variables only |