# AI Historical Facts TikTok Video (video template) > A faceless vertical video built from AI-generated images and a synthetic voiceover — this example narrates historical facts, but the format takes any script. Swap the topic list and schedule renders to post daily without filming anything. ## Overview - **Page**: https://shotstack.io/studio/templates/automated-tiktok-video-historical-facts/ - **Output**: MP4, 720x1280 (9:16), 25 fps - **Length**: 21s - **Timeline**: 9 clips on 6 tracks; assets: caption, image, text, text-to-image, text-to-speech - **Render endpoint (sandbox, free, watermarked)**: POST https://api.shotstack.io/edit/stage/render with header `x-api-key` - **Production**: same request against https://api.shotstack.io/edit/v1/render with a v1 key - **Preview in the browser (no account)**: https://shotstack.studio/#json=eyJ0aW1lbGluZSI6eyJiYWNrZ3JvdW5kIjoiIzAwMDAwMCIsInRyYWNrcyI6W3siY2xpcHMiOlt7ImFzc2V0Ijp7InR5cGUiOiJ0ZXh0IiwidGV4dCI6Int7IEhFQURMSU5FIH19IiwiYWxpZ25tZW50Ijp7Imhvcml6b250YWwiOiJjZW50ZXIiLCJ2ZXJ0aWNhbCI6ImNlbnRlciJ9LCJmb250Ijp7ImNvbG9yIjoiIzAwMDAwMCIsImZhbWlseSI6Ik1vbnRzZXJyYXQgRXh0cmFCb2xkIiwic2l6ZSI6IjYwIiwibGluZUhlaWdodCI6MX0sIndpZHRoIjo0NjMsImhlaWdodCI6MjAwfSwic3RhcnQiOjAsImxlbmd0aCI6ImF1dG8iLCJvZmZzZXQiOnsieCI6MCwieSI6MC4zMDl9LCJwb3NpdGlvbiI6ImNlbnRlciIsImZpdCI6Im5vbmUiLCJzY2FsZSI6MX1dfSx7ImNsaXBzIjpbeyJsZW5ndGgiOiJhdXRvIiwiYXNzZXQiOnsidHlwZSI6ImltYWdlIiwic3JjIjoiaHR0cHM6Ly90ZW1wbGF0ZXMuc2hvdHN0YWNrLmlvL2F1dG9tYXRlZC10aWt0b2stdmlkZW8taGlzdG9yaWNhbC1mYWN0cy85YmRjY2U4NC1hMDBmLTQ2ZTUtYWY5Yy01YjFlMjE2M2ZkZWMucG5nIn0sInN0YXJ0IjowLCJzY2FsZSI6MC4yLCJvZmZzZXQiOnsieCI6MCwieSI6MC4zMDh9LCJwb3NpdGlvbiI6ImNlbnRlciJ9XX0seyJjbGlwcyI6W3sibGVuZ3RoIjoiZW5kIiwiYXNzZXQiOnsidHlwZSI6ImNhcHRpb24iLCJzcmMiOiJhbGlhczovL1ZPSUNFT1ZFUiIsImJhY2tncm91bmQiOnsiY29sb3IiOiIjMDA5MWZmIiwicGFkZGluZyI6MjUsImJvcmRlclJhZGl1cyI6OX0sImZvbnQiOnsic2l6ZSI6IjMyIn19LCJzdGFydCI6MH1dfSx7ImNsaXBzIjpbeyJmaXQiOiJub25lIiwic2NhbGUiOjEsImxlbmd0aCI6NSwiYXNzZXQiOnsid2lkdGgiOiI3NjgiLCJoZWlnaHQiOiIxMjgwIiwidHlwZSI6InRleHQtdG8taW1hZ2UiLCJwcm9tcHQiOiJ7eyBJTUFHRV8yX1BST01QVCB9fSJ9LCJzdGFydCI6NCwidHJhbnNpdGlvbiI6eyJvdXQiOiJmYWRlIiwiaW4iOiJmYWRlIn0sImVmZmVjdCI6Inpvb21PdXQifSx7ImZpdCI6Im5vbmUiLCJzY2FsZSI6MSwibGVuZ3RoIjo1LCJhc3NldCI6eyJ3aWR0aCI6Ijc2OCIsImhlaWdodCI6IjEyODAiLCJ0eXBlIjoidGV4dC10by1pbWFnZSIsInByb21wdCI6Int7IElNQUdFXzRfUFJPTVBUIH19In0sInN0YXJ0IjoxMiwidHJhbnNpdGlvbiI6eyJvdXQiOiJmYWRlIiwiaW4iOiJmYWRlIn0sImVmZmVjdCI6InNsaWRlUmlnaHQifV19LHsiY2xpcHMiOlt7Imxlbmd0aCI6NSwiYXNzZXQiOnsid2lkdGgiOiI3NjgiLCJoZWlnaHQiOiIxMjgwIiwidHlwZSI6InRleHQtdG8taW1hZ2UiLCJwcm9tcHQiOiJ7eyBJTUFHRV8xX1BST01QVCB9fSJ9LCJzdGFydCI6MCwidHJhbnNpdGlvbiI6eyJvdXQiOiJmYWRlIn0sImVmZmVjdCI6Inpvb21JbiIsInBvc2l0aW9uIjoiY2VudGVyIn0seyJmaXQiOiJub25lIiwic2NhbGUiOjEsImxlbmd0aCI6NSwiYXNzZXQiOnsid2lkdGgiOiI3NjgiLCJoZWlnaHQiOiIxMjgwIiwidHlwZSI6InRleHQtdG8taW1hZ2UiLCJwcm9tcHQiOiJ7eyBJTUFHRV8zX1BST01QVCB9fSJ9LCJzdGFydCI6OCwidHJhbnNpdGlvbiI6eyJvdXQiOiJmYWRlIiwiaW4iOiJmYWRlIn0sImVmZmVjdCI6InNsaWRlTGVmdCIsIm9mZnNldCI6eyJ4IjowLjAyMSwieSI6MH0sInBvc2l0aW9uIjoiY2VudGVyIn0seyJmaXQiOiJub25lIiwic2NhbGUiOjEsImxlbmd0aCI6NSwiYXNzZXQiOnsid2lkdGgiOiI3NjgiLCJoZWlnaHQiOiIxMjgwIiwidHlwZSI6InRleHQtdG8taW1hZ2UiLCJwcm9tcHQiOiJ7eyBJTUFHRV81X1BST01QVCB9fSJ9LCJzdGFydCI6MTYsInRyYW5zaXRpb24iOnsib3V0IjoiZmFkZSIsImluIjoiZmFkZSJ9LCJlZmZlY3QiOiJzbGlkZVVwIn1dfSx7ImNsaXBzIjpbeyJsZW5ndGgiOiJhdXRvIiwiYXNzZXQiOnsidm9pY2UiOiJBbXkiLCJ0ZXh0Ijoie3tWT0lDRU9WRVJ9fSIsInR5cGUiOiJ0ZXh0LXRvLXNwZWVjaCJ9LCJzdGFydCI6MCwiYWxpYXMiOiJWT0lDRU9WRVIifV19XX0sIm91dHB1dCI6eyJmb3JtYXQiOiJtcDQiLCJmcHMiOjI1LCJzaXplIjp7IndpZHRoIjo3MjAsImhlaWdodCI6MTI4MH19LCJtZXJnZSI6W3siZmluZCI6IkhFQURMSU5FIiwicmVwbGFjZSI6IkRhbmNpbmcgUGxhZ3VlIn0seyJmaW5kIjoiVk9JQ0VPVkVSIiwicmVwbGFjZSI6IkRpZCB5b3Uga25vdyB0aGF0IGluIDE1MTgsIGEgYml6YXJyZSAnZGFuY2luZyBwbGFndWUnIGJyb2tlIG91dCBpbiBTdHJhc2JvdXJnPyBGb3IgZGF5cywgcGVvcGxlIGRhbmNlZCB1bmNvbnRyb2xsYWJseSBpbiB0aGUgc3RyZWV0cywgd2l0aCBubyBrbm93biBjYXVzZS4gU29tZSBldmVuIGNvbGxhcHNlZCBmcm9tIGV4aGF1c3Rpb24gb3IgZGllZC4gSGlzdG9yaWFucyBhcmUgc3RpbGwgYmFmZmxlZCBieSB0aGlzIHN0cmFuZ2UgZXZlbnQsIHdoaWNoIHJlbWFpbnMgb25lIG9mIGhpc3RvcnkncyBtb3N0IG15c3RlcmlvdXMgZXBpZGVtaWNzLiJ9LHsiZmluZCI6IklNQUdFXzFfUFJPTVBUIiwicmVwbGFjZSI6IkNyZWF0ZSBhIGhhdW50aW5nIHlldCByZWFsaXN0aWMgc2NlbmUgb2YgYSBtZWRpZXZhbCBzdHJlZXQgaW4gU3RyYXNib3VyZywgZmlsbGVkIHdpdGggdG93bnNwZW9wbGUgZGFuY2luZyB1bmNvbnRyb2xsYWJseS4gVGhlIGxpZ2h0aW5nIHNob3VsZCBiZSBkaW0gYW5kIGF0bW9zcGhlcmljLCB3aXRoIHNoYWRvd3MgY2FzdCBieSB0aGUgbW9vbmxpZ2h0LCBoaWdobGlnaHRpbmcgdGhlIGVlcmllIGFuZCBjaGFvdGljIG5hdHVyZSBvZiB0aGUgZXZlbnQuIFRoZSBiYWNrZ3JvdW5kIHNob3VsZCBpbmNsdWRlIGRhcmtlbmVkIG1lZGlldmFsIGJ1aWxkaW5ncyBhbmQgdG9yY2hlcyBmbGlja2VyaW5nIGluIHRoZSBkaXN0YW5jZS4ifSx7ImZpbmQiOiJJTUFHRV8yX1BST01QVCIsInJlcGxhY2UiOiJEZXNpZ24gYSBkcmFtYXRpYyBjbG9zZS11cCBvZiBhIGdyb3VwIG9mIGluZGl2aWR1YWwgZGFuY2VycywgZXhoYXVzdGVkIGJ1dCBhdCBlYXNlLCBtaWQtbW92ZW1lbnQuIFRoZSBmb2N1cyBzaG91bGQgYmUgb24gdGhlaXIgaW50ZW5zaXR5LiBUaGUgbGlnaHRpbmcgc2hvdWxkIGJlIHNvZnQsIHdpdGggc3VidGxlIHNoYWRvd3MgY3JlYXRpbmcgZGVwdGguIn0seyJmaW5kIjoiSU1BR0VfM19QUk9NUFQiLCJyZXBsYWNlIjoiSWxsdXN0cmF0ZSBhIG1lZGlldmFsIHRvd24gc3F1YXJlIGluIFN0cmFzYm91cmcsIGZpbGxlZCB3aXRoIGEgbWl4IG9mIGRhbmNpbmcgdG93bnNwZW9wbGUgYW5kIGNvbmNlcm5lZCBvbmxvb2tlcnMuIFRoZSBzY2VuZSBzaG91bGQgZmVhdHVyZSB3YXJtIHRvcmNobGlnaHQgY29udHJhc3Rpbmcgd2l0aCB0aGUgY29vbCBtb29ubGlnaHQsIGNhc3RpbmcgYW4gb21pbm91cyBnbG93IG9uIHRoZSBjb2JibGVzdG9uZSBzdHJlZXRzLiBUaGUgYXJjaGl0ZWN0dXJlIHNob3VsZCBiZSBoaXN0b3JpY2FsbHkgYWNjdXJhdGUsIHdpdGggd29vZGVuIG1hcmtldCBzdGFsbHMgYW5kIHN0b25lIGJ1aWxkaW5ncyBzdXJyb3VuZGluZyB0aGUgc3F1YXJlLiJ9LHsiZmluZCI6IklNQUdFXzRfUFJPTVBUIiwicmVwbGFjZSI6IkdlbmVyYXRlIGFuIGltYWdlIG9mIHRvd24gb2ZmaWNpYWxzIGFuZCBkb2N0b3JzIHN0YW5kaW5nIG9uIHRoZSBlZGdlcyBvZiB0aGUgc2NlbmUsIG9ic2VydmluZyB0aGUgY2hhb3MuIFRoZXkgc2hvdWxkIGxvb2sgY29uZnVzZWQgYW5kIGRpc3RyZXNzZWQsIGhvbGRpbmcgc2Nyb2xscyBvciBtZWRpZXZhbCBtZWRpY2FsIGluc3RydW1lbnRzLiBUaGUgbGlnaHRpbmcgc2hvdWxkIGNyZWF0ZSBhIGNvbnRyYXN0IGJldHdlZW4gdGhlIHRvcmNobGlnaHQgYW5kIHRoZSBkYXJrLCBhZGRpbmcgYSBzZW5zZSBvZiB1cmdlbmN5IHRvIHRoZWlyIGV4cHJlc3Npb25zLiJ9LHsiZmluZCI6IklNQUdFXzVfUFJPTVBUIiwicmVwbGFjZSI6IkNyZWF0ZSBhIHN1cnJlYWwsIGFsbW9zdCBkcmVhbWxpa2UgZGVwaWN0aW9uIG9mIHRoZSBkYW5jZXJzLCB3aXRoIHRoZWlyIG1vdmVtZW50cyBiZWNvbWluZyBibHVycmVkIGFuZCBnaG9zdGx5LiBUaGUgYmFja2dyb3VuZCBzaG91bGQgYmUgZGFyaywgd2l0aCBkaW0gdG9yY2hsaWdodCBjYXN0aW5nIGxvbmcgc2hhZG93cywgd2hpbGUgdGhlIGRhbmNlcnMnIGZpZ3VyZXMgYXBwZWFyIGV4YWdnZXJhdGVkIGFuZCBvdGhlcndvcmxkbHksIHJlZmxlY3RpbmcgdGhlIG15c3RlcmlvdXMgbmF0dXJlIG9mIHRoZSBldmVudC4ifV19 - **Edit and save to an account**: https://dashboard.shotstack.io/studio/editor/automated-tiktok-video-historical-facts ## How to use this template as a workflow 1. Render it once with the JSON below to confirm the output. 2. Replace the values that change per row of data (merge fields or asset URLs). 3. Loop over your data (CSV, database, webhook payload) and send one render per row. Add a `callback` URL to the request so Shotstack notifies you when each video is ready instead of polling. 4. To keep the JSON out of your app, store it with the Templates endpoint and render by template ID with a `merge` array: https://shotstack.io/docs/guide/architecting-an-application/templates/ ## Customise This template has merge fields. Send a `merge` array with the request to replace them; do not edit the timeline JSON. | Field | Default | | --- | --- | | `{{ HEADLINE }}` | Dancing Plague | | `{{ VOICEOVER }}` | Did you know that in 1518, a bizarre 'dancing plague' broke out in Strasbourg? For days, people danced uncontrollably in the streets, with no known cause. Some even collapsed from exhaustion or died. Historians are still baffled by this strange event, which remains one of history's most mysterious epidemics. | | `{{ IMAGE_1_PROMPT }}` | Create a haunting yet realistic scene of a medieval street in Strasbourg, filled with townspeople dancing uncontrollably. The lighting should be dim and atmospheric, with shadows cast by the moonlight, highlighting the eerie and chaotic nature of the event. The background should include darkened medieval buildings and torches flickering in the distance. | | `{{ IMAGE_2_PROMPT }}` | Design a dramatic close-up of a group of individual dancers, exhausted but at ease, mid-movement. The focus should be on their intensity. The lighting should be soft, with subtle shadows creating depth. | | `{{ IMAGE_3_PROMPT }}` | Illustrate a medieval town square in Strasbourg, filled with a mix of dancing townspeople and concerned onlookers. The scene should feature warm torchlight contrasting with the cool moonlight, casting an ominous glow on the cobblestone streets. The architecture should be historically accurate, with wooden market stalls and stone buildings surrounding the square. | | `{{ IMAGE_4_PROMPT }}` | Generate an image of town officials and doctors standing on the edges of the scene, observing the chaos. They should look confused and distressed, holding scrolls or medieval medical instruments. The lighting should create a contrast between the torchlight and the dark, adding a sense of urgency to their expressions. | | `{{ IMAGE_5_PROMPT }}` | Create a surreal, almost dreamlike depiction of the dancers, with their movements becoming blurred and ghostly. The background should be dark, with dim torchlight casting long shadows, while the dancers' figures appear exaggerated and otherworldly, reflecting the mysterious nature of the event. | ## Template JSON ```json { "timeline": { "background": "#000000", "tracks": [ { "clips": [ { "asset": { "type": "text", "text": "{{ HEADLINE }}", "alignment": { "horizontal": "center", "vertical": "center" }, "font": { "color": "#000000", "family": "Montserrat ExtraBold", "size": "60", "lineHeight": 1 }, "width": 463, "height": 200 }, "start": 0, "length": "auto", "offset": { "x": 0, "y": 0.309 }, "position": "center", "fit": "none", "scale": 1 } ] }, { "clips": [ { "length": "auto", "asset": { "type": "image", "src": "https://templates.shotstack.io/automated-tiktok-video-historical-facts/9bdcce84-a00f-46e5-af9c-5b1e2163fdec.png" }, "start": 0, "scale": 0.2, "offset": { "x": 0, "y": 0.308 }, "position": "center" } ] }, { "clips": [ { "length": "end", "asset": { "type": "caption", "src": "alias://VOICEOVER", "background": { "color": "#0091ff", "padding": 25, "borderRadius": 9 }, "font": { "size": "32" } }, "start": 0 } ] }, { "clips": [ { "fit": "none", "scale": 1, "length": 5, "asset": { "width": "768", "height": "1280", "type": "text-to-image", "prompt": "{{ IMAGE_2_PROMPT }}" }, "start": 4, "transition": { "out": "fade", "in": "fade" }, "effect": "zoomOut" }, { "fit": "none", "scale": 1, "length": 5, "asset": { "width": "768", "height": "1280", "type": "text-to-image", "prompt": "{{ IMAGE_4_PROMPT }}" }, "start": 12, "transition": { "out": "fade", "in": "fade" }, "effect": "slideRight" } ] }, { "clips": [ { "length": 5, "asset": { "width": "768", "height": "1280", "type": "text-to-image", "prompt": "{{ IMAGE_1_PROMPT }}" }, "start": 0, "transition": { "out": "fade" }, "effect": "zoomIn", "position": "center" }, { "fit": "none", "scale": 1, "length": 5, "asset": { "width": "768", "height": "1280", "type": "text-to-image", "prompt": "{{ IMAGE_3_PROMPT }}" }, "start": 8, "transition": { "out": "fade", "in": "fade" }, "effect": "slideLeft", "offset": { "x": 0.021, "y": 0 }, "position": "center" }, { "fit": "none", "scale": 1, "length": 5, "asset": { "width": "768", "height": "1280", "type": "text-to-image", "prompt": "{{ IMAGE_5_PROMPT }}" }, "start": 16, "transition": { "out": "fade", "in": "fade" }, "effect": "slideUp" } ] }, { "clips": [ { "length": "auto", "asset": { "voice": "Amy", "text": "{{VOICEOVER}}", "type": "text-to-speech" }, "start": 0, "alias": "VOICEOVER" } ] } ] }, "output": { "format": "mp4", "fps": 25, "size": { "width": 720, "height": 1280 } }, "merge": [ { "find": "HEADLINE", "replace": "Dancing Plague" }, { "find": "VOICEOVER", "replace": "Did you know that in 1518, a bizarre 'dancing plague' broke out in Strasbourg? For days, people danced uncontrollably in the streets, with no known cause. Some even collapsed from exhaustion or died. Historians are still baffled by this strange event, which remains one of history's most mysterious epidemics." }, { "find": "IMAGE_1_PROMPT", "replace": "Create a haunting yet realistic scene of a medieval street in Strasbourg, filled with townspeople dancing uncontrollably. The lighting should be dim and atmospheric, with shadows cast by the moonlight, highlighting the eerie and chaotic nature of the event. The background should include darkened medieval buildings and torches flickering in the distance." }, { "find": "IMAGE_2_PROMPT", "replace": "Design a dramatic close-up of a group of individual dancers, exhausted but at ease, mid-movement. The focus should be on their intensity. The lighting should be soft, with subtle shadows creating depth." }, { "find": "IMAGE_3_PROMPT", "replace": "Illustrate a medieval town square in Strasbourg, filled with a mix of dancing townspeople and concerned onlookers. The scene should feature warm torchlight contrasting with the cool moonlight, casting an ominous glow on the cobblestone streets. The architecture should be historically accurate, with wooden market stalls and stone buildings surrounding the square." }, { "find": "IMAGE_4_PROMPT", "replace": "Generate an image of town officials and doctors standing on the edges of the scene, observing the chaos. They should look confused and distressed, holding scrolls or medieval medical instruments. The lighting should create a contrast between the torchlight and the dark, adding a sense of urgency to their expressions." }, { "find": "IMAGE_5_PROMPT", "replace": "Create a surreal, almost dreamlike depiction of the dancers, with their movements becoming blurred and ghostly. The background should be dark, with dim torchlight casting long shadows, while the dancers' figures appear exaggerated and otherworldly, reflecting the mysterious nature of the event." } ] } ``` ## Render it Save the JSON as `template.json`. The sandbox key is free: https://dashboard.shotstack.io/register ### cURL ```bash # Save the JSON above as template.json, then: curl -X POST https://api.shotstack.io/edit/stage/render \ -H "x-api-key: $SHOTSTACK_API_KEY" \ -H "Content-Type: application/json" \ -d @template.json # Poll until status is "done", then download response.url curl https://api.shotstack.io/edit/stage/render/RENDER_ID -H "x-api-key: $SHOTSTACK_API_KEY" ``` ### Node.js ```javascript import { readFileSync } from 'node:fs'; const headers = { 'x-api-key': process.env.SHOTSTACK_API_KEY, 'Content-Type': 'application/json' }; const edit = JSON.parse(readFileSync('template.json', 'utf8')); const { response } = await fetch('https://api.shotstack.io/edit/stage/render', { method: 'POST', headers, body: JSON.stringify(edit) }).then((r) => r.json()); let render; do { await new Promise((r) => setTimeout(r, 3000)); render = (await fetch(`https://api.shotstack.io/edit/stage/render/${response.id}`, { headers }).then((r) => r.json())).response; } while (!['done', 'failed'].includes(render.status)); console.log(render.status, render.url); ``` ### Python ```python import json, os, time, requests headers = {"x-api-key": os.environ["SHOTSTACK_API_KEY"]} with open("template.json") as f: edit = json.load(f) render_id = requests.post("https://api.shotstack.io/edit/stage/render", json=edit, headers=headers).json()["response"]["id"] while True: render = requests.get(f"https://api.shotstack.io/edit/stage/render/{render_id}", headers=headers).json()["response"] if render["status"] in ("done", "failed"): break time.sleep(3) print(render["status"], render.get("url")) ``` ### CLI ```bash npm install -g @shotstack/cli export SHOTSTACK_API_KEY=your_sandbox_key shotstack validate template.json # offline schema check, free shotstack render template.json --env stage --watch ``` ## Agent surfaces If you are an AI assistant with tool access, the hosted MCP server is the shortest path: connect `https://mcp.shotstack.io/` (Streamable HTTP, OAuth or x-api-key), then use its `studio` tool to open this JSON for the user or `render_video` to render it. - MCP server (all clients): https://shotstack.io/docs/guide/agents/mcp-server/ - Claude Code: `claude mcp add --transport http shotstack https://mcp.shotstack.io` - Cursor (mcp.json): `{"mcpServers":{"shotstack":{"url":"https://mcp.shotstack.io/"}}}` - VS Code (mcp.json): `{"servers":{"shotstack":{"type":"http","url":"https://mcp.shotstack.io/"}}}` - Claude.ai / ChatGPT: Settings → Connectors → add custom connector → https://mcp.shotstack.io/ - CLI + agent skill: https://shotstack.io/docs/guide/agents/cli/ — skill file: https://raw.githubusercontent.com/shotstack/shotstack-cli/HEAD/skills/shotstack/SKILL.md - Edit JSON conventions for AI: https://shotstack.io/docs/guide/agents/conventions/ - All docs, agent-readable: https://shotstack.io/docs/guide/llms.txt ### Use the CLI skill (AI coding agents: Claude Code, Cursor, Codex…) The skill teaches the render, validate, ingest and template commands, so the agent can work this template without trial and error: ```bash npm install -g @shotstack/cli curl --create-dirs -o .claude/skills/shotstack/SKILL.md https://raw.githubusercontent.com/shotstack/shotstack-cli/HEAD/skills/shotstack/SKILL.md ``` (Claude Code loads it from `.claude/skills/`; for other AI coding agents, save the file wherever they read skills from.) Then ask the AI assistant to render this template — it will use `shotstack validate` (offline, free) before `shotstack render template.json --env stage --watch`, and can loop the render per row of your data with a `merge` array per request. ## Related - Bulk-create videos from a CSV: https://shotstack.io/learn/bulk-create-videos-from-csv-and-ai/ - Webhooks: https://shotstack.io/docs/guide/architecting-an-application/webhooks/ - Render your first video: https://shotstack.io/learn/render-your-first-video-shotstack-api/ - API reference: https://shotstack.io/docs/api/ - All agent-readable docs: https://shotstack.io/llms.txt