Templates and formats
A template is how a clip is drawn. It comes in variants, which are cuts of the same idea, in versions, which are builds, and in ratios, which are the shapes it can be drawn at. What matters to a developer is that a template publishes the exact document it accepts, so you can generate a client from it rather than guess.
On the dashboard the templates a workspace is offered are on Clip studio, under Choose a template, where Create clip makes a video from one on its own; that half of the API is direct export.
| Method | Path | Permission |
|---|---|---|
GET | /v1/templates | templates:read |
GET | /v1/templates/{templateId}/reference | templates:read |
GET | /v1/templates/{templateId}/reference/{ratio} | templates:read |
GET | /v1/templates/{templateId}/reference/{ratio}/still | templates:read |
GET | /v1/templates/{templateId}/reference-sheet | templates:read |
POST | /v1/templates/{templateId}/validate | templates:read |
GET | /v1/formats/templates | templates:read |
GET | /v1/formats/template/{templateId} | templates:read |
GET | /v1/formats/feed/{feedId} | templates:read |
GET | /v1/formats/feed/{source}/{format} | templates:read |
GET | /v1/catalogue | templates:read |
/v1/catalogue, /v1/formats/templates, /v1/formats/template/{id} and /v1/formats/feed/... are
served without authentication as well. What shape a template accepts is a product description, not
customer data, and a producer needs it before it has a reason to authenticate. Nothing in them says
who uses a template or what has been sent to it. POST /v1/templates/{templateId}/validate is a
POST that only reads, so it needs templates:read and nothing more.
Ask a template what it accepts
This is the call to build a producer around.

curl http://localhost:4000/v1/formats/template/tpl_dd7e6b264fb8
The answer carries four things: keys, a human-readable description of every input; jsonSchema,
the same thing as JSON Schema, for generating a client; example, a worked payload that satisfies
it; and ratios, the shapes this build comes in. Shortened here: keys lists every input, with its
label, description, limits and example, and jsonSchema holds every one of them too.
{
"templateId": "tpl_dd7e6b264fb8",
"templateName": "Big number",
"variant": "Corporate glass",
"version": "1.0.0",
"ratios": ["9x16", "4x5", "1x1", "16x9", "2x3"],
"keys": {
"format": "reelwire.keys/1",
"summary": "One figure counted up to its value, with what it is, its change and the window it happened in, and up to six more figures after it, one at a time. metaData is the post's title, descriptions and hashtags and is never drawn.",
"keys": [
{
"key": "clipData",
"type": "group",
"label": "Clip data",
"description": "Everything drawn: a kicker, what the figure is, the figure with its prefix and unit, the window it happened in, an optional change, a line of context, up to six more figures each on a page of its own, the source and the look.",
"required": true,
"keys": [
{ "key": "kicker", "type": "text", "label": "Kicker", "description": "A word above everything, such as BREAKING or JUST IN.", "required": false, "maxLength": 20, "example": "Breaking" },
{ "key": "label", "type": "text", "label": "What the figure is", "description": "Read before the figure, so the number lands with its meaning.", "required": true, "maxLength": 70, "example": "Wiped off the value of US tech stocks" },
{ "key": "value", "type": "number", "label": "The figure", "required": true, "decimals": 4, "example": 740 }
]
}
]
},
"jsonSchema": {
"type": "object",
"properties": { "clipData": { "type": "object", "title": "Clip data" }, "metaData": { "type": "object", "title": "Meta data" }, "locales": { "type": "object" } },
"required": ["clipData"],
"additionalProperties": false
},
"example": {
"clipData": {
"kicker": "Breaking",
"label": "Wiped off the value of US tech stocks",
"value": 740,
"prefix": "$",
"unit": "billion",
"window": "in 5 minutes",
"change": { "value": -2.1, "unit": "%", "label": "Nasdaq 100 today" },
"note": "The biggest five-minute drop since March, minutes after the inflation figures came in above forecasts",
"more": [
{ "label": "Nvidia, the biggest faller among the chip makers", "value": 118.4, "prefix": "$", "unit": "", "window": "at the close", "change": { "value": -4.8, "unit": "%", "label": "on the day" }, "note": "Chip makers led the fall as bond yields jumped." },
{ "label": "Gold, where the money went", "value": 2412, "prefix": "$", "unit": "an ounce", "window": "a record close", "change": { "value": 1.2, "unit": "%", "label": "on the day" }, "note": "Investors bought the metal as a shelter from the sell-off." }
],
"source": "Exchange data, 15:35 New York time",
"look": { "theme": "auto", "pace": "auto", "corners": "auto", "align": "auto", "logo": "auto" }
},
"metaData": {
"title": "740 billion dollars off US tech stocks in five minutes",
"captionTiny": "740 billion dollars wiped off US tech stocks in five minutes after the inflation figures.",
"captionShort": "740 billion dollars were wiped off US tech stocks in five minutes after the inflation figures came in above forecasts. The Nasdaq 100 closed 2.1 percent lower.",
"captionMedium": "740 billion dollars were wiped off US tech stocks in five minutes after the inflation figures came in above forecasts. It was the biggest five-minute drop since March. The Nasdaq 100 closed the day 2.1 percent lower, led by the largest chip makers.",
"captionLong": "740 billion dollars were wiped off US tech stocks in five minutes after the inflation figures came in above forecasts. It was the biggest five-minute drop since March. The Nasdaq 100 closed the day 2.1 percent lower, led by the largest chip makers. Markets now expect fewer rate cuts this year than they did a week ago.",
"hashtags": ["markets", "nasdaq", "tech"]
}
}
}
Two halves, always. clipData is drawn in the clip. metaData is the post's title, descriptions and
hashtags, and is never drawn on the video. Beside them every template also takes an optional
soundtrack, { "url": "media://workshop-track.mp3" }: an MP3 or WAV file from the media library that
plays for this clip alone in place of the brand's soundtrack, as the brand's would (over the same parts,
fading out at the end). A template with its own sound settings, such as Overlay and Slideshow, decides
over it as over the brand's. It is not in the worked example, and a file that is not a sound is a
problem at /soundtrack/url. Every key is in the example, optional ones included, so
you see the whole shape rather than the least that would pass. look is the same eleven switches in
every format of the collections (theme, pace, corners, text alignment, the logo's plate, the logo's
size and form, the top line, the footer line, the background pattern and the brand's background), each auto or off, the style's own choice, unless you set it. A theme left on auto draws what the brand's style names as its theme, and otherwise the template style's own. logo is auto (the style's plate, or a light or a dark one where the logo would not read on it: more than a fifth of the pixels at its edge under 2:1), free (no plate) or light, dark or brand (that plate in every style, also where the style draws none), and the brand's logoOnDark stands in wherever it reads better. logoForm is auto (the brand's mark where the style's logo space is round, or where a wide logo would be shrunk under three fifths of the height the style planned), mark or full. background is true to draw the brand's background picture or film under any theme, under a veil of the theme's page; under brand it is always drawn. logoSize is auto (Standard), small
(a fifth smaller, with its plate) or large (a quarter larger wherever the style has room for it).
hideHeader is true to leave out the line at the top, the logo, the title line and the style's
decoration around them, so the content starts at the top; a brand leaves it out of every clip with
"header": { "enabled": false } in its style. hideFooter is true to leave out the brand's footer
line and whatever the style draws only to carry it, so the content reaches further down; the presenter
and the source line stay. A brand leaves it out of every clip with "footer": { "enabled": false }.
pattern is the fine texture behind the content: auto keeps the style's own (Corporate glass's dots,
Swiss grid's column lines; some styles draw none), none leaves the background plain, and dots, grid
or lines (diagonal lines) draw that pattern faintly instead, the same in every style, in the colour
of the page. The style's larger background, its glows, rays or aurora, stays whichever you choose.
Intros and outros have their own look: theme, pace, corners, text alignment, logo, logoSize,
logoForm, Brand background and Extra time at the end. Their logo and logoForm are the formats' above, except that
logoForm auto draws the mark where the style's logo space is round or the full logo would be drawn smaller than
80 pixels on a 1080-pixel side. Stingers and overlays take the same logo and logoForm as the formats; over an overlay's video
nothing is judged, so auto draws the style's plate and the brand's own logo. The outro takes a slogan (up to 60 characters; left out,
the brand's identity.slogan is drawn, as on the intro), a qrUrl (an https address of up to 100 characters
the QR code leads to, drawn without a website too), cta.action text (the words with no icon; none
leaves the whole call to action out), a detail kind website, and a handle's platform (instagram,
tiktok, youtube, linkedin, x, facebook, threads, pinterest, snapchat, telegram, whatsapp,
discord, mastodon, bluesky; linkedin draws the @ sign).
What auto means in each variant. The answer carries styleDefaults: for each switch whose auto is the
style's own choice, the value it stands for in that variant, keyed by the switch's JSON pointer, such as
{ "/clipData/look/theme": "brand", "/clipData/reveal": "assemble" }. Sending that value draws exactly what
auto draws. The JSON Schema says it in the label too, "The style's own (Brand colours)".
locales inside the content is how one event carries several languages: beside the body, per
language code, only what differs, such as "locales": { "de": { "clipData": { "label": "..." } } }.
The JSON Schema describes it, and the worked example leaves it out. Each channel takes its own
language's copy laid over the default, so a language with no copy still renders, with the default.
The description comes in four lengths because the platforms do, and each platform posts the longest
that leaves room for the brand's description, link and hashtags: the tiny one (captionTiny, up to
200 characters) on Pinterest, Threads and X, the short one (captionShort, 500) on Telegram, the
medium one (captionMedium, 1,500) on Discord, Facebook Reels, Instagram, LinkedIn, Slack and TikTok,
and the long one (captionLong, 4,000) on Facebook Feed and
YouTube. The JSON Schema's titles say the same, "Tiny description (Pinterest, Threads, X)" and so on.
A length left out is filled from the next shorter one written, or failing that the next longer one,
which the platform's limit then shortens; so content from before the tiny length gives those
platforms its short one. A channel on No specific platform hands over every length, because the
person posting it chooses where it goes.
Leave metaData out, or send it with nothing in it, on a feed or a stream and the post text is
generated from clipData: the clip's own title as the post's title (its title and label, or a
headline), the kicker, that title, a second line (subline) and any points (bullets) as the
description, and up to four hashtags from the longer words of the title and kicker. Send any of it
and only what you sent is used: a description with no title goes out with no title. A post on a
post list says only what was written, and only an empty title is filled
in there.
A picture is a file from your media library, and nothing else. Every image field is
{ "url": "...", "alt": "..." }, and url takes media:// followed by the file's id, or its name,
which is how a template's own example names a picture (Spotlight's is media://example-image.svg,
one of the files every new workspace's library starts with); the JSON Schema calls the two parts
"Picture" and "Alt text". A web address is
refused and the refusal names the field: a 400 on a feed, a post list or a direct export, and
unmapped with the reason on a stream. Upload the picture to the
media library first, then refer to it.
A video is the same, for a video. A template that plays one of your videos (the Overlay template)
takes { "url": "media://...", "alt": "..." } the same way, and the clip is as long as the video,
60 seconds at most: a video that would play longer is refused unless trim chooses a shorter part of it. Reelwire measures the file itself and writes its length into the field as
durationMs, so you never send it, and anything sent there is replaced. Such a clip plays the video's
own sound rather than the brand's soundtrack, without the brand's stinger, intro and outro, and counts
as one video of your allowance whatever its length. Every new workspace's library starts with
example-video.mp4, which the template's own example names.
The Overlay takes a picture as well. Name a picture from your library in the same field
(media://example-image.jpg, say) and the brand is laid over it exactly as over a video, cropped to
fill each shape the same way. A picture has no length, so the clip runs the seconds you send beside
it, from 3 to 60, or 10 without them. Reelwire writes which it is into the field as kind, video or
image, beside the length, and replaces anything sent there too. With a picture the clip is worn like
any other: your brand's soundtrack plays over it, and its stinger, intro and outro go round it.
Ask /v1/formats/template/{templateId} for a particular cut or build with
?variant=Corporate%20glass&version=1.0.0. Without them you get the first variant and the newest
build. A variant the template does not have is a 400 that names the
ones it has. version here takes an exact build only: leave it out for the newest, because latest
is looked for as a version and is a 404.
Ask per variant where the variants differ. Every style of a collection (Big number in Corporate
glass, Editorial or Data terminal) takes the same content, so any variant answers for all of them.
The vertical templates are different: Finance, Influencer, Retail, Tech and Public bodies each hold
ten use cases as variants, and each variant takes its own content (a Market update is not an Advisor
intro). Ask for those with ?variant=, and send each post or event the content of the variant it is
drawn with.
Ask by feed instead
A producer usually knows it sends central bank decisions, not which template draws those. Which template a feed uses is Reelwire's decision and changes without the producer being told, so ask by the feed and follow.
curl http://localhost:4000/v1/formats/feed/fd_c16f5268064a
The answer is the same document, resolved through the feed's current binding. GET /v1/formats/feed/{source}/{format} is the same answer addressed by the two slugs.
Ask for a design of your own
POST /v1/templates/custom-design asks Reelwire for a design made especially for this workspace, for
when none of the styles on the shelf is yours. It takes about (what the design should be, at least a
sentence), and optionally liked, disliked and brandId, and sends one email to Reelwire with the person
asking as its Reply-To; it answers { "sent": true, "answerTo": "you@example.com" }, the address Reelwire
writes back to. What Reelwire then makes is a template offered to your workspace alone. Nothing is promised
by the request itself, neither a price nor a date. Five requests a day per workspace; it needs Clip studio:
write.
Check content before you send it
POST /v1/templates/{templateId}/validate checks content against the build it would be drawn with
and stores nothing: the check a post list's post gets when it is saved and Create clip gets before it
renders, against the variant's own keys, with every picture the content names looked up in this
workspace's media library as well. On the dashboard it is the Validate input link under a
content editor.
| Field | Required | What it is |
|---|---|---|
data | yes | The content, as one object: clipData, metaData and any locales. |
variant | no | The cut to check against, by name. Absent is the template's first. |
version | no | An exact build, or "latest". Absent is the newest. |
ratio | no | The shape it will be drawn in, such as 9x16, for the warnings. Absent is every shape the build draws. |
curl http://localhost:4000/v1/templates/tpl_dd7e6b264fb8/validate \
-H "Authorization: Bearer rw_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"variant": "Corporate glass",
"data": { "clipData": { "label": "Ten-year Bund yield", "valeu": 2.41 } }
}'
{
"ok": false,
"templateId": "tpl_dd7e6b264fb8",
"variant": "Corporate glass",
"version": "1.0.0",
"problems": [
{ "path": "/clipData", "message": "missing value" },
{ "path": "/clipData", "message": "has a field this template does not take: valeu" }
],
"warnings": []
}
Content that does not fit still answers 200: ok says whether it would be taken, and problems
names each field at fault, as a JSON Pointer, in words: missing, not a field this template takes,
over its limit, or not one of the values it accepts. A picture the library does not hold is a
problem at its own field, such as /clipData/picture/url with "media://harbour.jpg is not in this
workspace's media library: upload it, or choose a file the library has", because the shape alone
cannot tell, and the clip would draw a missing picture. variant in the answer is the cut that was
checked, the first when you named none. A variant the template does not have, or a version it does
not hold, is a 400 naming what there is; data that is not one object is a 400 too.
Warnings
Content that fits can still not look or sound the way you expect, and warnings says so in the same
shape as problems: a path and a message. A warning never refuses anything: the content saves,
posts and renders as it is. They are worked out only for content without problems, and only for the
templates whose keys ask for them, such as Overlay and Slideshow:
- A picture or video enlarged until it looks soft. Where a picture fills the whole frame, Reelwire
measures the file and works out how far it is enlarged at each shape, after the picture fit, the
focus point and the zoom. Above 1.5 times it warns, naming the worst shape and the factor: "Slide
1's picture is enlarged 1.8 times to fill the 9x16 frame and will look soft. Choose a larger
picture or show it whole." Send
ratioto hear about one shape only. - A video asked to play its own sound that has none. Many free videos carry no sound at all, so an Overlay set to its video's own sound would be silent: "This video has no sound of its own. Choose music or mix to give it the brand soundtrack."
- An Overlay's foot crowded once its title is moved down there, with the captions, the presenter and the footer line beside it.
The check also holds what the content asks of the clock, and refuses what has no right way to be
drawn: a title or a logo set to show from and until seconds whose Until comes before its From, or whose
From is past the clip's end; a caption page that ends before it starts; a part of a video (trim) that
ends before it starts or starts after the video's end; and slides whose own lengths add up to more than
the clip may run (a slideshow runs a minute at most), naming the total.
{
"ok": true,
"templateId": "tpl_2518c80fd3fb",
"variant": "Soft friendly",
"version": "1.0.0",
"problems": [],
"warnings": [
{
"path": "/clipData/slides/0/picture",
"message": "Slide 1's picture is enlarged 1.8 times to fill the 9x16 frame and will look soft. Choose a larger picture or show it whole."
}
]
}
On the dashboard the warnings appear under Validate input, after the line saying the content fits.
What is on the shelf
GET /v1/formats/templates is every template that can describe itself: one entry per variant of
each template holding a build with a key mapping, at its newest build, in the order of the
templates' names. That is exactly the set a producer could usefully be pointed at. keys counts the
top-level inputs, which for every template in the catalogue are clipData and metaData.
{
"templates": [
{ "templateId": "tpl_06dc2554e5ac", "templateName": "Number grid", "variant": "Data terminal", "version": "1.0.0", "keys": 2 },
{ "templateId": "tpl_06dc2554e5ac", "templateName": "Number grid", "variant": "Editorial", "version": "1.0.0", "keys": 2 }
]
}
A template with no build yet is a name on a shelf with nothing to describe, so it is not listed rather than listed and unusable.
GET /v1/templates is the workspace's own view: what this account is offered, joined with the
templates it already meets through a feed, a stream or a post list, each with its inputSchema,
duration, ratios and variants. catalogue is the offered ones, as Clip studio's Choose a
template lists them, each with its kind; templates is every build the workspace may use or name, and offered says
whether it may pick that one for a stream or a post, or only name it because something of its own
already draws with it.
{
"catalogue": [
{
"id": "tpl_dd7e6b264fb8",
"name": "Big number",
"family": "Collections",
"description": "One figure counted up to exactly what was sent, with what it is, when it happened and its change, and up to six more figures after it, one at a time: 8 to 35 seconds. In ten styles, each wearing your brand's colours, fonts, logo, presenter and background.",
"kind": "style-and-format",
"variants": ["Corporate glass", "Bento grid", "Broadcast news", "Editorial", "Swiss grid", "Neo-brutalist", "Soft friendly", "Data terminal", "Keynote minimal", "Kinetic type"]
}
],
"templates": [
{
"templateId": "tpl_dbadb7ef4a70",
"offered": true,
"version": "1.0.0",
"name": "Spotlight",
"contentStyle": "motion-graphics",
"family": "Template projects",
"milestone": 1,
"ratios": ["9x16", "4x5", "1x1", "16x9", "2x3"],
"duration": { "mode": "formula", "baseFrames": 180, "perItemFrames": 30, "itemsPath": "/clipData/facts", "freeItems": 0, "minFrames": 240, "maxFrames": 420 },
"subvariants": [],
"overridableStyle": ["*"],
"inputSchema": { "type": "object", "required": ["clipData"] },
"variants": [
{ "name": "Bento grid", "versions": ["1.0.0"] },
{ "name": "Broadcast news", "versions": ["1.0.0"] },
{ "name": "Corporate glass", "versions": ["1.0.0"] },
{ "name": "Creator native", "versions": ["1.0.0"] },
{ "name": "Editorial", "versions": ["1.0.0"] },
{ "name": "Keynote minimal", "versions": ["1.0.0"] },
{ "name": "Neo-brutalist", "versions": ["1.0.0"] },
{ "name": "Soft friendly", "versions": ["1.0.0"] },
{ "name": "Swiss grid", "versions": ["1.0.0"] }
],
"descriptorSha": "19a9365d778eb833f0f267dad6c17eb3a41a2fc9a5b961f0c784e97a1db84c4f",
"syncedAt": "2026-09-23T18:46:36.864Z"
}
]
}
duration says how long a clip runs, in frames at the build's frame rate (30 a second): most
templates' grow with what you send (here, from 180 frames plus 30 for each fact, held between 240
and 420), so more content makes a longer clip rather than a crowded one. variants in templates lists each cut by
name with the builds uploaded for it, in alphabetical order; catalogue lists the names in the
order the Templates catalogue shows them, the first being the one used when none is named.
kind says what kind of collection a template is, by what changes between its variants: package
(different things in one style, such as a package made for one workspace), looks (one thing, such as an
intro or an outro, in every style) or style-and-format (one format in the styles that suit it). It
is null for a template not filed as any of them yet.
inputSchema is the template's own, shortened here: for a vertical template, whose variants take
different content, ask /v1/formats/template/{templateId} per
variant instead.
descriptorSha changes whenever the build behind a version changes, so a client that caches a
template can tell when to read it again.
What a workspace is offered follows the industries its owner chose (see Your industries): a template graded core or possible for one of them. The owner changes them on the dashboard; no key can. Taking an industry away leaves what already draws with a template alone.
GET /v1/catalogue is the shipped feed catalogue rather than the template shelf: every feed Reelwire
carries, whatever one workspace is offered, each format with its fd_ id, its payload schema
(jsonSchema, the key mapping of the template behind it), a worked example (examples),
templateIds, markets and maxAgeSeconds, how old an event may be before it is kept but never
published: a day for the ready-made feeds. markets is the grade the feed was shipped with per
market id, core, possible or bad; the ids are brokers (the market called Finance), tech,
public and retail. It is served with an etag and cache-control: public, max-age=30, so a client that has
seen the version can skip the parse. What one workspace is offered is
GET /v1/feeds.
Which builds exist
curl http://localhost:4000/v1/templates/tpl_dd7e6b264fb8/reference \
-H "Authorization: Bearer rw_your_key_here"
{
"templateId": "tpl_dd7e6b264fb8",
"name": "Big number",
"variants": [
{ "name": "Corporate glass", "versions": [{ "version": "1.0.0", "ratios": ["9x16", "4x5", "1x1", "16x9", "2x3"] }] },
{ "name": "Bento grid", "versions": [{ "version": "1.0.0", "ratios": ["9x16", "4x5", "1x1", "16x9", "2x3"] }] },
{ "name": "Broadcast news", "versions": [{ "version": "1.0.0", "ratios": ["9x16", "4x5", "1x1", "16x9", "2x3"] }] }
]
}
Shortened here to three of Big number's ten variants. They come in the order the Templates catalogue lists them, each with its builds newest first.
GET /v1/templates/{templateId}/reference/{ratio} returns the reference clip itself, so you can
see what a template looks like before you commit to it. It is a video, not JSON:
HTTP/1.1 200 OK
content-type: video/mp4
etag: "5f3346d28eb21a9d24768c82d387c7a66708cf6561511a9f3837c8455f385fa2-9x16"
cache-control: private, no-cache
x-template-version: 1.0.0
Narrow it with ?variant=Corporate%20glass&version=1.0.0; here version=latest is the newest build. A
ratio that is not NxM is a 400 that says "No such shape", and a variant, version or shape the
build has no clip for is a 404. Send the etag back as If-None-Match and an unchanged build
answers 304 with nothing to download.
GET /v1/templates/{templateId}/reference/{ratio}/still is one frame of that clip, a JPEG 480 pixels
wide taken nine tenths of the way through, the picture Clip studio's cards show. It takes the same
?variant= and ?version=, and its etag, x-template-version and 404s work as the clip's do.
GET /v1/templates/{templateId}/reference-sheet is one picture, a JPEG rather than JSON, of a variant
drawn with its worked example in several brands, looks and shapes, so you can see at a glance how it
wears a brand. It takes the same ?variant= and ?version=, carries an etag that works the same
way and x-template-version, and is a 404 for a build that carries no sheet.
Versions and variants
A version names a build. "latest" is a real answer rather than an absence, and it is the
default: it follows the newest build, resolved at the moment something renders.
For now every template is at version 1.0.0. An improvement to a template replaces its 1.0.0
build rather than adding a version, so a channel pinned to 1.0.0 and one on "latest" draw the
same thing today. The content a template accepts does not change with a new build.
A variant is a cut of the same template. In a collection, such as Big number, each variant is a visual style and every style takes the same content; in a vertical template, such as Finance, each variant is a use case with content of its own. Which variant and which version are the subscribing channel's choice, the post's on a post list, or the video's in a direct export; they are never the producer's. See Channels.
POST /v1/templates/sync, which appears in the route list, mirrors the template registry. It is
Reelwire's own, for its staff, and refused to every key: nothing a producer or a publisher does
needs it.
Mistakes people make
Writing the payload by hand from an example. Take jsonSchema and generate a type. The example
is there to check yourself against, not to copy.
Rendering a clip to find out whether the content fits. POST /v1/templates/{templateId}/validate
answers the same question at once, names every field at fault, pictures the library lacks included,
and spends nothing.
Putting drawn content in metaData. It is never drawn. Headlines and figures go in clipData.
Sending locales beside the content. It goes inside the content, where the template validates
it.
Pinning a version because it is there. A pin stops following new versions. Pin when you have a reason to, not by default.
Assuming every template comes in every shape. ratios is per build. A channel on a surface the
template does not draw has nothing to render.
Addressing a feed by its slugs in stored configuration. Slugs are words and words get edited.
Use the fd_ id.