# E-commerce product videos at scale: turning catalog images into clips with an API Most product catalogs have plenty of still images and very few videos. A typical store has three to eight photos per SKU: a hero shot, a few angles, a lifestyle image, maybe a size chart. Videos are rare because each one costs a shoot, an editor, and someone's afternoon. Marketplaces, social feeds, and product detail pages increasingly rank and convert better with motion, though, so that gap now costs sales. Image-to-video models close most of the gap. You give the model the product photos you already have plus a short prompt, and it returns a 5–15 second clip. Doing this for one product is easy. Doing it for 20,000 SKUs means building a pipeline that is cheap, predictable, and doesn't fall over when a request fails. This article walks through that pipeline using [RelayDance](https://relaydance.com), an OpenAI-compatible API in front of ByteDance's Seedance video models (plus HappyHorse and Grok Imagine). --- ## Why an API instead of a web tool Web-based video generators are fine for making ten hero clips by hand. At catalog scale you need: - **Batch submission** driven by your product database, not by copy-pasting into a UI - **Deterministic inputs**: the same images, prompt template, aspect ratio, and duration for every SKU in a category - **Async handling**: video generation takes time, so you need polling or webhooks instead of a browser tab left open - **Cost control**: per-second pricing you can budget against SKU count RelayDance speaks the OpenAI protocol, so existing tooling mostly carries over. According to the official relaydance.com/docs: "Set base_url to https://relaydance.com/v1 and keep your OpenAI SDK." You also don't need a BytePlus enterprise account or KYC to reach Seedance. You create an API key at [relaydance.com/console](https://relaydance.com/console) and pay as you go with USDT or a Stripe card. --- ## The pipeline at a glance Product DB ──► Prompt builder ──► POST /v1/video/generations ──► task_id │ ┌──────────── webhook (callback_url) ◄───────┤ │ or │ └──────────── GET /v1/video/generations/{id} ◄┘ │ status = succeeded │ download video ──► CDN ──► PDP / feeds / ads The pipeline has four stages: pick the images, build the prompt, submit the job, and collect the result. --- ## Step 1: Choose reference images per SKU Seedance accepts reference media in `metadata.content[]`, and you refer to them in the prompt as `@image1` through `@imageN`. Each request can include: - up to **9 reference images** - up to **3 reference videos** - up to **3 audio tracks** - clips up to **15 seconds** long For most catalog work, two or three images are enough. More references can help with complex products, but they also give the model more ways to drift. A good default: | Slot | Image | Purpose | |---|---|---| | `@image1` | Clean hero shot on white | Product identity: shape, color, logo | | `@image2` | Secondary angle (back/side) | Keeps the model from inventing hidden geometry | | `@image3` | Lifestyle or texture close-up (optional) | Material, scale, context | Use your highest-resolution originals, not thumbnails that have already been compressed for the web. Artifacts in the input show up in the output. --- ## Step 2: Template your prompts by category Don't write prompts per product. Write one per category, then fill in attributes from your catalog. python TEMPLATES = { "sneakers": ( "Slow 360-degree turntable of the shoe in @image1, matching the " "back detail shown in @image2. Soft studio lighting, seamless light " "grey background, subtle floor reflection. Colorway: {color}. " "No text, no hands, product stays centered." ), "handbags": ( "The bag from @image1 rests on a marble surface; camera slowly " "pushes in to reveal the {material} texture seen in @image3. " "Warm natural window light. No people, no added logos." ), } def build_prompt(sku): return TEMPLATES[sku["category"]].format(**sku["attributes"]) Some patterns hold up well across thousands of SKUs: - **Restrict motion.** Turntables, slow push-ins, and gentle parallax keep the product looking like the product. Dramatic camera moves are where hallucinated details appear. - **Say what not to do.** "No text, no hands, no added logos" removes a whole class of rejects. - **Name the reference roles.** "The shoe in @image1, back detail in @image2" works better than listing the images without explanation. --- ## Step 3: Submit the job Video tasks go to `POST /v1/video/generations` with `model`, `prompt`, `seconds`, and a `metadata` object (`ratio`, `resolution`, `generate_audio`, `callback_url`, `content[]`). Video generation is asynchronous, so the response gives you a task ID rather than a finished file. python import os, requests BASE = "https://relaydance.com/v1" HEADERS = { "Authorization": f"Bearer {os.environ['RELAYDANCE_API_KEY']}", "Content-Type": "application/json", } def submit(sku): payload = { "model": "doubao-seedance-2-5-1080p", # see /models for current IDs "prompt": build_prompt(sku), "seconds": 5, "metadata": { "ratio": "9:16", # vertical for social / mobile PDP "resolution": "1080p", "generate_audio": False, # most PDP video autoplays muted "callback_url": "https://shop.example.com/hooks/relaydance", "content": [ # check the docs for the exact reference-media item schema {"type": "image_url", "image_url": {"url": url}} for url in sku["image_urls"][:3] ], }, } r = requests.post(f"{BASE}/video/generations", json=payload, headers=HEADERS) r.raise_for_status() return r.json() # contains the task_id Store the returned task ID against the SKU in your database right away. That one row is what makes the pipeline resumable after a crash. The exact model IDs and the structure of `content[]` items are documented in the [RelayDance docs](https://relaydance.com/docs). Pin them in config rather than hard-coding them in several places. --- ## Step 4: Collect results with webhooks or polling **Webhooks (recommended at scale).** When you set `metadata.callback_url`, RelayDance POSTs the task's final state to your server. Your handler looks up the SKU by task ID, downloads the video, pushes it to your CDN, and marks the row done. Nothing sits in a loop. **Polling (fine for small batches or local testing).** Call `GET /v1/video/generations/{task_id}` until `status` is `succeeded` or `failed`: python import time def wait_for(task_id, interval=10): while True: r = requests.get(f"{BASE}/video/generations/{task_id}", headers=HEADERS) r.raise_for_status() task = r.json() if task["status"] in ("succeeded", "failed"): return task # on success, the result contains the video URL time.sleep(interval) Even if you use webhooks, run a polling sweep as a safety net: a nightly job that checks any task still marked "pending" after an hour. Webhooks can be lost when your endpoint is down during a deploy, and the sweep catches those. Download the video to your own storage instead of linking to the generation URL directly. Your product pages shouldn't depend on someone else's URL staying live. --- ## Retries are cheap Retries matter in a batch pipeline. Some fraction of jobs will fail because of a transient error, an input the model rejects, or a timeout. According to the official relaydance.com docs, "Failed or errored requests are never billed." That makes the retry policy simple. When a task comes back `failed`, requeue it with exponential backoff, up to two or three attempts. If a SKU still fails after that, send it to manual review, because the cause is usually the source images (heavy watermark, cluttered background, or a low-res thumbnail). A failure costs you time but not money. Failures are free, but bad outputs that succeed are not. Budget for some regenerations caused by quality problems, as covered in the QA section below. --- ## Budgeting a catalog run Pricing is per generated second. Current rates from [relaydance.com/models](https://relaydance.com/models): | Model / tier | Price | 5-second clip | |---|---|---| | Seedance Fast | ~$0.152 / s | ~$0.76 | | Seedance 2.0, 720p | ~$0.190 / s | ~$0.95 | | Seedance 2.0, 1080p | ~$0.470 / s | ~$2.35 | | Seedance 2.5, 1080p (`doubao-seedance-2-5-1080p`, added 2026-10-10) | ~$0.711 / s | ~$3.56 | | Seedance native 4K | ~$4.90 per 5-s clip | ~$4.90 | Example: a 10,000-SKU catalog with one 5-second clip per product. - **Seedance Fast**: about **$7,600** - **Seedance 2.0 720p**: about **$9,500** - **Seedance 2.0 1080p**: about **$23,500** - **Seedance 2.5 1080p**: about **$35,550** A tiered approach usually wins: 1. **Draft pass on Seedance Fast** for the whole catalog, to validate prompt templates and find products whose source images don't work. 2. **Production pass at 720p** for the long tail. Marketplace thumbnails and in-feed autoplay rarely benefit from more resolution. 3. **1080p or Seedance 2.5** for your top sellers and hero PDPs, where quality affects conversion. 4. **Native 4K** only for campaign assets and paid placements that actually display at that size. These numbers are a snapshot. Check [the models page](https://relaydance.com/models) for live rates before you commit to a budget. --- ## Bonus: fix the input images first Weak source images are the most common cause of weak product videos. RelayDance also exposes image generation at `POST /v1/images/generations`, which you can use to clean up references before the video stage: swap a cluttered background for a seamless one, or produce a consistent lifestyle shot across a product line. The billing for gpt-image-2 suits this preprocessing step. Per [relaydance.com/models](https://relaydance.com/models), image output is free and only input is billed. Image-to-image starts at about CNY 0.035, and 4K output costs the same as 1K. You can therefore produce the highest-resolution reference at no extra cost, which matters because the video model works from whatever detail you give it. Because the endpoint is OpenAI-compatible, the standard SDK works: python from openai import OpenAI client = OpenAI( base_url="https://relaydance.com/v1", api_key=os.environ["RELAYDANCE_API_KEY"], ) # client.images.generate(...) / client.images.edit(...) as usual --- ## Quality control before anything ships Generative video will sometimes get the product wrong, for example by adding a stripe, merging two buttons, or rendering the logo slightly off. Shipping that on a product page is a returns and trust problem. Build QA into the pipeline: - **Automated first pass**: extract a few frames per clip and compare them against the hero image using embedding similarity. Flag anything below a threshold. - **Human spot-check**: review 100% of hero SKUs and a random sample of the long tail. A reviewer can approve or reject a 5-second clip in a few seconds. - **Reject reasons feed back into templates**: if "handbags" keeps failing on strap geometry, change the prompt or add an `@image2` angle for that category. - **Keep the still image as the fallback**: if a clip isn't approved, the PDP shows photos as before. Nothing breaks. --- ## Putting it together A production setup looks like this: 1. A **queue** (SQS, Redis, Postgres-backed, whatever you already run) of SKUs that need video 2. **Workers** that build prompts from category templates and submit to `/v1/video/generations` with a `callback_url` 3. A **webhook handler** that stores finished videos and marks tasks complete 4. A **sweeper** that polls stale tasks and requeues failures, which costs nothing because failed requests aren't billed 5. A **QA gate** before anything is published to the storefront Start with one category and a few hundred SKUs on Seedance Fast, tune the templates until the reject rate is acceptable, then scale up and move the SKUs that matter to higher tiers. Endpoint and payload details are in the [RelayDance docs](https://relaydance.com/docs), and current per-model pricing is at [relaydance.com/models](https://relaydance.com/models).
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