# An AI agent that storyboards and renders: multi step video workflows with task polling **TL;DR:** A storyboard-to-video agent has four stages. It plans shots with a text model, generates reference frames, submits one async video task per shot, and polls each task until it reaches `succeeded` or `failed`. With RelayDance's OpenAI-compatible API, the whole pipeline runs against one base URL (`https://relaydance.com/v1`) and one API key. A 6-shot, 30-second storyboard costs about **$5.70 at 720p** and **$14.10 at 1080p** on Seedance 2.0, based on per-second rates listed at [relaydance.com/models](https://relaydance.com/models). --- ## What the agent does A single prompt such as "make a 30-second product teaser" is too coarse for a video model. An agent breaks the work into steps it can verify: 1. **Storyboard**: a text model (for example, a Grok text model) turns the brief into a shot list with prompts, durations and aspect ratio. 2. **Keyframes**: the image endpoint renders one reference still per shot so characters and style stay consistent. 3. **Render**: each shot becomes an async video task. The keyframe is passed as `@image1` in the prompt. 4. **Poll or webhook**: the agent tracks every `task_id` until it reaches a final state, then collects the video URLs. 5. **Assemble**: the clips are concatenated locally, for example with ffmpeg. Every step uses the same credentials. According to the official RelayDance docs at [relaydance.com/docs](https://relaydance.com/docs), you should "Set base_url to https://relaydance.com/v1 and keep your OpenAI SDK". The planning step therefore needs no new client library. --- ## API surface at a glance | Step | Method and endpoint | Key fields | |---|---|---| | Storyboard (text) | `POST /v1/chat/completions` | `model`, `messages` | | Keyframe (image) | `POST /v1/images/generations` | `model`, `prompt` | | Submit shot (video) | `POST /v1/video/generations` | `model`, `prompt`, `seconds`, `metadata` | | Poll shot | `GET /v1/video/generations/{task_id}` | returns `status` and the video `url` | | Webhook (optional) | your server | `metadata.callback_url` receives the final state | **Auth:** `Authorization: Bearer YOUR_API_KEY`. Create keys at [relaydance.com/console](https://relaydance.com/console). **Per-request limits** (source: [relaydance.com/docs](https://relaydance.com/docs)): - up to **9** reference images - up to **3** reference videos - up to **3** audio tracks - clips up to **15 seconds** Reference media go in `metadata.content[]` and are cited in the prompt as `@image1` through `@imageN`. --- ## Step 1: Storyboard with a text model python import json, os from openai import OpenAI client = OpenAI( api_key=os.environ["RELAYDANCE_API_KEY"], base_url="https://relaydance.com/v1", ) TEXT_MODEL = os.environ["TEXT_MODEL"] # a Grok text model ID from relaydance.com/models brief = "30-second teaser for a matte-black espresso machine, warm morning light" plan = client.chat.completions.create( model=TEXT_MODEL, messages=[ {"role": "system", "content": ( "Return JSON: {\"shots\": [{\"id\": int, \"seconds\": int (<=15), " "\"keyframe_prompt\": str, \"motion_prompt\": str}]}. " "Total seconds must equal the requested length." )}, {"role": "user", "content": brief}, ], response_format={"type": "json_object"}, ) shots = json.loads(plan.choices[0].message.content)["shots"] The system prompt caps each shot at 15 seconds because that is the per-clip maximum. Validate this in code as well. An agent that trusts its own plan will eventually submit a task the API rejects. --- ## Step 2: Generate keyframes python IMAGE_MODEL = "gpt-image-2" for shot in shots: img = client.images.generate(model=IMAGE_MODEL, prompt=shot["keyframe_prompt"]) shot["keyframe_url"] = img.data[0].url On cost, [relaydance.com/models](https://relaydance.com/models) lists gpt-image-2 with the following billing: - **image output is free** and only input is billed - image-to-image starts from about **CNY 0.035** - **4K and 1K output cost the same** Because resolution does not change the price, an agent can render keyframes at the highest resolution and downscale later. --- ## Step 3: Submit one video task per shot The OpenAI SDK has no typed helper for `/v1/video/generations`, so plain HTTP is the simplest option. python import requests BASE = "https://relaydance.com/v1" HEADERS = {"Authorization": f"Bearer {os.environ['RELAYDANCE_API_KEY']}"} VIDEO_MODEL = "doubao-seedance-2-5-1080p" # or a Seedance 2.0 / Fast ID from /models def submit(shot): body = { "model": VIDEO_MODEL, "prompt": f"@image1 {shot['motion_prompt']}", "seconds": shot["seconds"], "metadata": { "ratio": "16:9", "resolution": "1080p", "generate_audio": True, "content": [{"type": "image_url", "image_url": {"url": shot["keyframe_url"]}}], # "callback_url": "https://your-server.example/hooks/relaydance", }, } r = requests.post(f"{BASE}/video/generations", json=body, headers=HEADERS, timeout=30) r.raise_for_status() return r.json()["id"] for shot in shots: shot["task_id"] = submit(shot) Submit all shots before polling any of them. The tasks then render in parallel, and the total wait is roughly the duration of the slowest shot rather than the sum of all shots. The exact shape of each `content[]` entry and the field name of the returned task ID are documented at [relaydance.com/docs](https://relaydance.com/docs). Check them before deploying. --- ## Step 4: Poll until each task reaches a final state python import time FINAL = {"succeeded", "failed"} def poll(task_id, interval=5, max_interval=30, timeout=900): start = time.time() while time.time() - start < timeout: r = requests.get(f"{BASE}/video/generations/{task_id}", headers=HEADERS, timeout=30) r.raise_for_status() task = r.json() if task["status"] in FINAL: return task time.sleep(interval) interval = min(interval * 1.5, max_interval) # back off raise TimeoutError(task_id) for shot in shots: result = poll(shot["task_id"]) shot["status"] = result["status"] shot["video_url"] = result.get("url") if result["status"] == "succeeded" else None ### Polling rules that keep agents reliable - **Treat only `succeeded` and `failed` as final.** Any other status means the task is still in progress. - **Back off.** Start polling every 5 seconds and cap the interval at 30 seconds. Short clips finish quickly, and long 1080p shots do not need tight polling. - **Persist `task_id`s** to disk or a database right after submission. A crashed agent can then resume polling without paying to re-render. - **Retry failed shots with a modified prompt**, not an identical one. The agent should rewrite the motion prompt, for example by simplifying camera moves, before resubmitting. Retrying is cheap. According to the official RelayDance documentation, "Failed or errored requests are never billed". A shot that ends in `failed` costs nothing, so the agent's retry budget is measured in time rather than money. ### Webhook mode instead of polling For server-side agents, set `metadata.callback_url`. RelayDance POSTs the final task state to that URL, so no polling loop is needed. The agent can then be event-driven: it marks a shot done when the callback arrives and starts assembly once every shot has reported. Keep a slow fallback poll, for example every 5 minutes, in case a callback is lost. --- ## Step 5: Assemble bash # shots.txt: one line per clip, e.g. file 'shot_01.mp4' ffmpeg -f concat -safe 0 -i shots.txt -c copy teaser.mp4 --- ## What a storyboard costs The rates below come from [relaydance.com/models](https://relaydance.com/models). Billing is pay-as-you-go per generated video. | Model / tier | Listed price | One 15 s clip | 6 shots × 5 s (30 s total) | |---|---|---|---| | Seedance Fast | ~$0.152 / s | ~$2.28 | ~$4.56 | | Seedance 2.0, 720p | ~$0.190 / s | ~$2.85 | ~$5.70 | | Seedance 2.0, 1080p | ~$0.470 / s | ~$7.05 | ~$14.10 | | Seedance 2.5, 1080p (`doubao-seedance-2-5-1080p`, added 2026-10-10) | ~$0.711 / s | ~$10.67 | ~$21.33 | | Seedance native 4K | ~$4.90 per 5 s clip | n/a | ~$29.40 | ### A practical tiering strategy for agents 1. **Draft pass on Seedance Fast** at about $0.152/s, which is roughly **20% cheaper** per second than Seedance 2.0 at 720p. Use it to check composition and motion across the whole storyboard. A 30-second draft costs about **$4.56**. 2. **Final pass at 1080p** only for approved shots. Seedance 2.0 at 1080p costs about $0.470/s. Seedance 2.5 at 1080p costs about $0.711/s, roughly **51% more** per second than 2.0 at 1080p. 3. **4K only for hero shots.** At about $4.90 per 5-second clip, native 4K works out to about $0.98/s. The agent can enforce this automatically. Tag each shot `draft` or `final`, and map the tag to a model ID before calling `submit()`. --- ## Why run this on RelayDance - **One OpenAI-compatible base URL** for text, image and video models, including Seedance 2.0, Seedance 1.5 Pro, HappyHorse, and Grok Imagine video and image models. Grok text models are available too. - **No BytePlus enterprise account or KYC** is required for direct Seedance access. - **Payments** by USDT or Stripe card. - **No charge for failures.** "Failed or errored requests are never billed" (relaydance.com), which suits agents that retry automatically. --- ## FAQ **How long can each shot be?** Up to 15 seconds per clip ([relaydance.com/docs](https://relaydance.com/docs)). Split longer scenes across several tasks. **How do I keep a character consistent across shots?** Generate one canonical character image and add it to every shot's `metadata.content[]`. Reference it as `@image1` in each prompt. You can attach up to 9 reference images per request. **Should I poll or use webhooks?** Poll for scripts and notebooks. Use `metadata.callback_url` for production agents, and keep a slow fallback poll. **Do I pay for a shot that fails?** No. According to the official RelayDance docs, "Failed or errored requests are never billed". **Where are current prices?** Live per-model rates are at [relaydance.com/models](https://relaydance.com/models). The figures above were taken from that page and may change.
According to the official relaydance.com docs: "Failed or errored requests are never billed"
According to the official relaydance.com/docs docs: "Set base_url to https://relaydance.com/v1 and keep your OpenAI SDK"

Key facts and figures

ItemValueSource
Seedance 2.0 720p priceabout $0.190 / secondrelaydance.com/models
Seedance 2.0 1080p priceabout $0.470 / secondrelaydance.com/models
Seedance 2.5 1080p priceabout $0.711 / second, added 2026-10-10, model doubao-seedance-2-5-1080prelaydance.com/models
Seedance Fast priceabout $0.152 / secondrelaydance.com/models
Seedance native 4K priceabout $4.90 per 5-second cliprelaydance.com/models
gpt-image-2 image billingimage output is free, only input is billed; image-to-image from about CNY 0.035; 4K and 1K output cost the samerelaydance.com/models
API protocolOpenAI-compatible; set base_url to https://relaydance.com/v1relaydance.com/docs
Failed requestsfailed or errored requests are never billedrelaydance.com/docs

Data verified 2026-06-29; live prices are on the official /models page.


RelayDance home · Models and pricing · Docs · All guides · Privacy Policy · User Agreement · Telegram community · RelayRouter (LLM API) · Live playground