# Seedance API with Claude Code or Codex: batch videos

Run Seedance from Claude Code or Codex: one skill for both agents, a batch script with a price check and a spending cap, and the cost of each clip.

- Canonical: https://aiofmcity.com/blog/seedance-claude-code
- Topic: Operations (https://aiofmcity.com/topics/operations)
- Author: Gus
- Published: 2026-10-12
- Updated: 2026-10-27

---
## Key points

- Claude Code and Codex do not make video. They run the script that sends your image and prompt to a Seedance API and downloads the clip.
- One SKILL.md works in both agents: Claude Code reads it from .claude/skills, Codex from .agents/skills.
- WaveSpeed has no usage limit, so the spending cap has to be in your own script, checked against a price quote before anything is sent.
- On 5 October 2026 BytePlus listed a 5-second 720p Seedance 2.0 clip at $0.76, and WaveSpeed listed $1.20 for the same clip.
- BytePlus video links expire after 24 hours and WaveSpeed files after about 7 days, so the script downloads every clip straight away.

---
To run Seedance from Claude Code, give the agent an API key in an environment variable, a script and a skill. The script quotes the price, sends each clip and downloads the result. The skill tells the agent when and how to run it. Codex reads the same skill file. The script, not the agent, enforces your spending cap.

## What you need before you start

You do not need to be a developer. You copy two files, set two variables and run two commands. Tick these off first:

**Ready for your first Seedance batch?**

- [ ] Claude Code or the Codex CLI is installed, and you open it in one project folder. — That folder holds the script, the skill, your images and the finished clips.
- [ ] Python 3 is installed, with the requests library. — Install the library with: pip install requests. On Windows, type py instead of python if python is not found.
- [ ] You have a WaveSpeed account, an API key and a small prepaid balance. — $5 covers four 5-second 720p Seedance 2.0 clips at $1.20 each. Leave automatic top-up switched off.
- [ ] Approved images of your persona are in the folder persona/approved/. — Only your own generated character. No real person and no celebrity look-alike.
- [ ] You have written three test clips into jobs.csv. — One line per clip: image, prompt, length, resolution and aspect ratio. The format is below.

## How Seedance, Claude Code and Codex work together

The agent does not make the video. Claude Code or Codex reads your instructions and runs a script on your computer. The script talks to the Seedance API.

Claude itself cannot make images or video:

> "Claude is an image understanding model only. It can interpret and analyze images, but it cannot generate, produce, edit, manipulate, or create images."
>
> — Source: Claude Docs — Vision, read 2026-10-05 — https://platform.claude.com/docs/en/build-with-claude/vision

So every Seedance setup has the same three parts:

| Part | What it is | Where it lives |
| --- | --- | --- |
| API key | Your key for BytePlus or WaveSpeed | An environment variable, never in a file the agent reads |
| Script | Quotes, sends, waits, downloads | `scripts/seedance_batch.py` in your project |
| Skill | Tells the agent when to run the script and what to check | `.claude/skills/` and `.agents/skills/` |

A skill is only instructions plus optional files. The money is spent by the script, so the limits belong in the script.

Here is the whole batch, step by step, with who does each step:

_Diagram: The agent only starts the script. The script holds the spending cap, and the batch stops twice for you: before any money is spent, and before anything is posted._

1. **You:** Write jobs.csv — One line per clip, only approved persona images
2. **Agent:** Check the image paths and run plan — Stops if an image is outside persona/approved/
3. **Script:** Upload the images and quote every clip — WaveSpeed pricing API, full inputs. Writes plan.json
4. **You (checkpoint):** Approve the quoted total — Nothing is sent without your yes
5. **Script:** Check the cap and your balance — Over either one: the batch stops before the first clip
6. **Script:** Send one clip, wait, download it — Saved unchanged, with a JSON file of prompt, task ID and quote
7. **You (checkpoint):** Watch every clip in full — Face, hands, the last second
8. **You:** Label as AI and post by hand — Or with the platform scheduler

## Which Seedance API to use: BytePlus or WaveSpeed

BytePlus ModelArk is ByteDance's own API for Seedance, and it was cheaper on 5 October 2026. WaveSpeed is a reseller with one key for many models and a simpler start. The script in this guide uses WaveSpeed, because its pricing API can quote every clip before you spend anything.

| 5-second 720p clip, 5 October 2026 | BytePlus ModelArk | WaveSpeed |
| --- | --- | --- |
| Seedance 2.0 | $0.76 | $1.20 |
| Seedance 2.5 | $1.156 | $1.80 |
| A batch of 20 Seedance 2.0 clips | $15.20 | $24.00 |

Two warnings about these numbers. BytePlus gives its examples for 16:9, and your 9:16 clip is billed by its own pixel count. WaveSpeed's "starts at" price is the cheapest setting, not the default 720p clip. [What AI video costs per clip](https://aiofmcity.com/blog/ai-video-models-for-personas#what-ai-video-costs-per-clip) compares Seedance with the other video models, and [the model price list](https://aiofmcity.com/model-prices) is updated on its own date. The prices come from these pages:

> Price examples for input without video, 16:9, 5-second output. Dreamina Seedance 2.0: 480p "0.35 per video", 720p "0.76 per video", 1080p "1.87 per video". Dreamina Seedance 2.5: 480p "0.514 per video", 720p "1.156 per video", 1080p "2.843 per video". Prices in USD. Token use is an estimate; the actual use is "subject to the `usage.completion_tokens` parameter returned after the API call."
>
> — Source: BytePlus ModelArk — Model pricing, read 2026-10-21 — https://docs.byteplus.com/en/docs/ModelArk/1544106

> "Base rate (480p): $0.60 per 5 seconds". 720p is "2x the 480p price", so 720p for 5 s costs $1.20. Duration 4 to 15 seconds. The page also says the model "starts at $0.54 per run" and that this "is the base price".
>
> — Source: WaveSpeedAI — Seedance 2.0 Image-to-Video, read 2026-10-21 — https://wavespeed.ai/models/bytedance/seedance-2.0/image-to-video

> Per 5 seconds: 480p $0.90, 720p $1.80, 1080p $4.50, 4k $9.00. Duration 4 to 30 seconds, default 5. Resolution default 720p. The page also says the model "starts at $0.81 per run".
>
> — Source: WaveSpeedAI — Seedance 2.5 Image-to-Video, read 2026-10-21 — https://wavespeed.ai/models/bytedance/seedance-2.5/image-to-video

For a batch, five other differences matter as much as the price:

| For a batch | BytePlus ModelArk | WaveSpeed |
| --- | --- | --- |
| Longest Seedance 2.0 clip | 15 seconds | 15 seconds |
| Clips rendering at once, new account | 3 | 2, or 300 after any top-up |
| Before the first clip | Balance above USD 30, a savings plan or a resource pack | Enough prepaid credit for the clip |
| Real human faces as input | Not supported | Not mentioned on the model pages |
| Download links last | 24 hours | About 7 days |

The sources for this table:

> `dreamina-seedance-2-5-260628`: duration 4 to 30 s. `dreamina-seedance-2-0-260128`: duration 4 to 15 s. For both (non-4K), default for individual users: "Max RPM: 180", "Max concurrency: 3".
>
> — Source: BytePlus ModelArk — Model list, read 2026-10-05 — https://docs.byteplus.com/en/docs/ModelArk/1330310

> Before enabling Seedance 2.0 and 2.5, you need one of these: a BytePlus account balance above USD 30 (recommended), an AI Savings Plan at the USD 30 tier or above, or a Seedance resource pack. The 2.0 and 2.5 models "do not support directly uploading reference images or videos that contain real human faces." With `watermark` set to true, "An AI Generated watermark will be displayed in the lower right corner of the generated video."
>
> — Source: BytePlus ModelArk — Create a video generation task, read 2026-10-05 — https://docs.byteplus.com/en/docs/ModelArk/1520757

> Bronze, the default for new users: 5 predictions per minute and 2 at the same time. Silver, after "Any successful single top-up below $1,000": 500 per minute and 300 at the same time.
>
> — Source: WaveSpeedAI docs — Account Levels & Rate Limits, read 2026-10-05 — https://wavespeed.ai/docs/account-levels

Use only images of your own generated persona as the first frame. A real person's face is blocked on BytePlus, and it is not allowed on most platforms you post to. The WaveSpeed model pages do not mention the face rule.

## A Seedance batch script with a spending cap

The script works in two steps. `plan` uploads your images and asks WaveSpeed for the price of every clip. `run` refuses to start if the total is over your cap or over your balance, then sends one clip at a time.

WaveSpeed's pricing API gives a real quote only when you send the full inputs:

> "When `inputs` is omitted, `price` is the model's configured base price." With `inputs`, the price "is calculated using that object and the model's schema defaults." `discounted_price` is the "Amount payable in USD after the effective discount". "Submitting an inference request calculates its price again." "The server enforces the final charge."
>
> — Source: WaveSpeedAI docs — Pricing API, read 2026-10-05 — https://wavespeed.ai/docs/pricing-api

WaveSpeed also warns against sending a job twice:

> "If the connection drops after the server accepts a request, blindly retrying can create and bill a duplicate prediction. Safe GET result queries can be retried."
>
> — Source: WaveSpeedAI docs — Get Started with API, read 2026-10-05 — https://wavespeed.ai/docs/get-started-api

The script below uses WaveSpeed's documented endpoints: price, balance, upload, submit and result. The key comes from the `WAVESPEED_API_KEY` environment variable, so it never appears in the file. Save it as `scripts/seedance_batch.py`:

```python
#!/usr/bin/env python3
"""Seedance batch on WaveSpeed with a spending cap.

  python scripts/seedance_batch.py plan jobs.csv   # upload images, quote every clip, write plan.json
  python scripts/seedance_batch.py run plan.json   # refuse if over cap or balance, then render

Needs WAVESPEED_API_KEY. Cap in SEEDANCE_MAX_USD (default 5).
"""
import csv, datetime, json, os, pathlib, sys, time
import requests

API = "https://api.wavespeed.ai/api/v3"
MODEL = os.environ.get("SEEDANCE_MODEL", "bytedance/seedance-2.0/image-to-video")
MAX_USD = float(os.environ.get("SEEDANCE_MAX_USD", "5"))
KEY = os.environ.get("WAVESPEED_API_KEY") or sys.exit("Set WAVESPEED_API_KEY first. Nothing was sent.")
HEADERS = {"Authorization": f"Bearer {KEY}"}
DONE = ("completed", "failed", "cancelled", "timeout", "deleted")

def call(method, path, **kwargs):
    for attempt in range(5):
        try:
            r = requests.request(method, API + path, headers=HEADERS, timeout=120, **kwargs)
        except requests.RequestException:
            if method == "GET":  # reading a result is safe to repeat
                time.sleep(10)
                continue
            raise  # never resend a POST: the job may already exist and be billed
        if r.status_code == 429:  # rate limit: nothing was created, so wait and try again
            time.sleep(15 * (attempt + 1))
            continue
        r.raise_for_status()  # any other error stops the script
        return r.json()["data"]
    sys.exit("Still failing after 5 tries. Stopping.")

def plan(jobs_csv):
    jobs = []
    with open(jobs_csv, newline="", encoding="utf-8") as f:
        for row in csv.DictReader(f):
            image = pathlib.Path(row["image"])
            url = call("POST", "/media/upload/binary",
                       files={"file": (image.name, image.read_bytes())})["download_url"]
            inputs = {"image": url, "prompt": row["prompt"], "duration": int(row["duration"]),
                      "resolution": row["resolution"], "aspect_ratio": row["aspect_ratio"],
                      "generate_audio": False}
            quote = call("POST", "/model/price", json={"model_id": MODEL, "inputs": inputs})
            jobs.append({"source": str(image), "inputs": inputs, "usd": quote["discounted_price"]})
    total = round(sum(j["usd"] for j in jobs), 2)
    pathlib.Path("plan.json").write_text(
        json.dumps({"model": MODEL, "total_usd": total, "jobs": jobs}, indent=2))
    print(f"{len(jobs)} clips, quoted total ${total}, cap ${MAX_USD}. Written to plan.json.")

def run(plan_file):
    p = json.loads(pathlib.Path(plan_file).read_text())
    balance = call("GET", "/balance")["balance"]
    if p["total_usd"] > MAX_USD:
        sys.exit(f"Quote ${p['total_usd']} is over the cap of ${MAX_USD}. Nothing was sent.")
    if p["total_usd"] > balance:
        sys.exit(f"Quote ${p['total_usd']} is over your balance of ${balance}. Nothing was sent.")
    out = pathlib.Path("out") / datetime.date.today().isoformat()
    out.mkdir(parents=True, exist_ok=True)
    spent = 0.0
    for n, job in enumerate(p["jobs"], 1):
        if spent + job["usd"] > MAX_USD:
            sys.exit(f"The next clip would pass the cap. Stopped after {n - 1} clips.")
        task = call("POST", "/" + p["model"], json=job["inputs"])
        spent += job["usd"]  # counted even if the clip fails
        while True:
            time.sleep(10)
            res = call("GET", f"/predictions/{task['id']}/result")
            if res["status"] in DONE:
                break
        for i, url in enumerate(res.get("outputs") or []):
            # Save the bytes as they come: no re-encoding, so the file keeps its metadata.
            (out / f"{n:03d}-{i}.mp4").write_bytes(requests.get(url, timeout=600).content)
        (out / f"{n:03d}.json").write_text(json.dumps(
            {"task": task["id"], "model": p["model"], "status": res["status"],
             "quoted_usd": job["usd"], "source": job["source"], "inputs": job["inputs"]}, indent=2))
        print(f"Clip {n}/{len(p['jobs'])}: {res['status']}. Spent so far: about ${spent:.2f}.")

if __name__ == "__main__":
    {"plan": plan, "run": run}[sys.argv[1]](sys.argv[2])
```

And the jobs file it reads, `jobs.csv`, one clip per line:

```csv
image,prompt,duration,resolution,aspect_ratio
persona/approved/cafe-01.png,"She lifts the cup, smiles and looks out of the window. Slow push-in, soft daylight. No subtitles.",5,720p,9:16
persona/approved/street-03.png,"She walks towards the camera and stops, wind in her hair. Handheld, eye level. No subtitles.",5,720p,9:16
```

What the parts of the script do, if you have never read Python:

- **The top lines** read your settings: the key, the model and the cap. If the key is missing, the script stops before it sends anything.
- **`call`** sends one request to WaveSpeed and returns the `data` part of the answer. It is the only place that talks to the API.
- **`plan`** reads `jobs.csv` line by line, uploads each image, builds the inputs for that clip and asks for its price. It writes everything to `plan.json`, which you can open in any text editor.
- **`run`** reads `plan.json`, checks the cap and the balance, and then sends the clips one by one. After each clip it saves the video and a JSON file next to it.

The inputs follow the Seedance 2.0 page on WaveSpeed. `aspect_ratio` 9:16 gives an upright clip for Reels and TikTok. The model adds sound by default, and the script switches it off with `generate_audio`. Set it to `True` if you want the model's sound, and the quote then includes it.

What each safety check does:

1. **The cap is checked twice.** Once for the whole batch before the first clip, and again before every clip, so an edited `plan.json` cannot slip past it.
2. **The balance is checked once.** If your prepaid balance cannot cover the quote, nothing is sent.
3. **A failed clip still counts as spent.** WaveSpeed's billing page does not say whether a failed task is charged, so the script assumes it is.
4. **A submission is never sent twice.** If the connection drops while a clip is being sent, the script stops. Reading a result is repeated, because that is safe.
5. **Rate limits are respected.** The script sends one clip at a time and waits after a 429 error, which fits even the Bronze level.
6. **Clips are saved unchanged.** A JSON file next to each clip keeps the prompt, the task ID and the quote.

Run it once by hand before you give it to an agent. Type `python scripts/seedance_batch.py plan jobs.csv`, open `plan.json` and check the total. Then type `python scripts/seedance_batch.py run plan.json` and watch the clips arrive in `out/` with today's date. If the connection dropped during a run, look for the last task ID in WaveSpeed's History before you send anything again.

To use the official BytePlus API instead, the shape is the same. You send a `POST` to `https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks` with `Authorization: Bearer $ARK_API_KEY`, a `model` such as `dreamina-seedance-2-0-260128`, and a `content` list with your text and an `image_url` whose `role` is `first_frame`. Then you poll the task until it is `succeeded`. For the quote, use BytePlus's price table above, and after each clip read `usage.completion_tokens`, which is what you are billed for.

### What the sources do not say: Finding a WaveSpeed setting that stops a batch at a spending limit

We looked for a WaveSpeed setting that stops generation once you have spent a fixed amount. There is none in the documentation.

The account levels page sets limits on predictions per minute and tasks at the same time, not on money. The pricing API gives a quote, and the docs say the server "calculates its price again" when you submit. The only monthly limit is for automatic top-ups, and that page says it is "not a usage or consumption limit". It is also off by default. The MCP server and the CLI offer a price quote and a balance check, but no maximum.

You can check this yourself. Open WaveSpeed's docs pages "Account levels", "How pricing works", "Pricing API" and "Monthly auto-recharge limit", and search each one for "limit", "budget" and "cap". Then read the command list in the wavespeed-cli README on GitHub. The safest limit you have is a small prepaid balance with automatic top-up switched off.

## One Seedance skill for Claude Code and Codex

Write the skill once and put it where both agents look. Claude Code and Codex both build on the same open standard.

> "Claude Code skills follow the Agent Skills open standard, which works across multiple AI tools." Project skills live in `.claude/skills/<skill-name>/SKILL.md`. A skill folder can be a symlink: "Claude Code reads SKILL.md from the target". `disable-model-invocation: true` prevents Claude "from automatically loading this skill. Use for workflows you want to trigger manually with /name."
>
> — Source: Claude Code Docs — Extend Claude with skills, read 2026-10-05 — https://code.claude.com/docs/en/skills

> "For repositories, Codex scans .agents/skills in every directory from your current working directory up to the repository root." The SKILL.md file "must include name and description". In Codex CLI, "run /skills or type $ to mention a skill". Optional `agents/openai.yaml` can set `allow_implicit_invocation: false`. "Codex supports symlinked skill folders."
>
> — Source: ChatGPT Learn — Build skills (Codex), read 2026-10-05 — https://learn.chatgpt.com/docs/build-skills

Here is the skill. Save it as `.claude/skills/seedance-batch/SKILL.md`:

```markdown
---
name: seedance-batch
description: Renders a batch of Seedance image-to-video clips of our AI persona through WaveSpeed. Use when the user asks for several clips from jobs.csv. Do not use for any real person.
---

# Seedance batch

1. Check that jobs.csv exists and that every image path starts with persona/approved/.
   If one does not, stop and say which line.
2. Run: python scripts/seedance_batch.py plan jobs.csv
3. Tell the user how many clips there are and the quoted total from plan.json.
   Wait for an explicit "yes". Do not start without it.
4. Run: python scripts/seedance_batch.py run plan.json
   Never change SEEDANCE_MAX_USD or SEEDANCE_MODEL yourself.
5. Report every clip that failed. Do not retry it without asking:
   a retry is a new task with its own price.
6. Do not post, caption, upload or share any clip. The user reviews every clip.

Rules
- Never print, log or paste the API key. If it is missing, ask the user to set it.
- Prompts stay strictly safe for work. The persona is an adult and fictional.
- No real people as references, no celebrity look-alikes.
```

Then make it visible to Codex. On macOS or Linux, create the `.agents/skills` folder and run `ln -s ../../.claude/skills/seedance-batch .agents/skills/seedance-batch` from your project root. On Windows, copying the folder is simpler. In Claude Code you start the skill with `/seedance-batch`, in Codex with `$seedance-batch`, or you just ask for the batch and the agent picks the skill.

Because the skill can spend money, you may want only you to start it. In Claude Code, add the line `disable-model-invocation: true` under `description` in the frontmatter. In Codex, add a small file to the skill folder:

```yaml
# seedance-batch/agents/openai.yaml (inside the skill folder)
policy:
  allow_implicit_invocation: false
```

The script refuses an over-cap batch either way.

## How Claude Code and Codex run the script: keys and permissions

Set the key in your shell before you start the agent, and let the agent ask before each paid run. Do not paste the key into the chat.

On Windows PowerShell:

```powershell
$env:WAVESPEED_API_KEY = "your-api-key"   # from wavespeed.ai/accesskey
$env:SEEDANCE_MAX_USD = "5"               # the most one batch may cost
claude                                    # or: codex
```

On macOS or Linux:

```bash
export WAVESPEED_API_KEY="your-api-key"   # from wavespeed.ai/accesskey
export SEEDANCE_MAX_USD="5"               # the most one batch may cost
claude                                    # or: codex
```

Both settings last only for this terminal window. The agent starts from the same window, so the script it runs can read the key, and the key never appears in the chat or in a file.

Claude Code asks before it runs a command you have not allowed:

> "When Claude asks permission to run a Bash command and you choose 'Yes, and don't ask again', Claude Code saves that permission approval" as an `allow` rule in your local settings file.
>
> — Source: Claude Code Docs — Settings, read 2026-10-05 — https://code.claude.com/docs/en/settings

Allow the `plan` step if you like, because it only uploads and quotes. Answer the `run` step yourself each time. A skill's `allowed-tools` field can also pre-approve commands, so do not list the `run` command there.

Codex blocks the network by default, and the script needs it:

> "By default, the agent runs with network access turned off." In the Auto preset, "Codex asks for approval to edit files outside the workspace or to run commands that require network access." For the CLI, the default `workspace-write` sandbox "keeps network access turned off unless you enable it in your configuration".
>
> — Source: ChatGPT Learn — Agent approvals and security (Codex), read 2026-10-05 — https://learn.chatgpt.com/docs/agent-approvals-security

So Codex asks you before both steps. That is the right default for a script that spends money. You can turn network access on in `config.toml` with `network_access = true` under `[sandbox_workspace_write]`. Then the approval for `run` is gone, and only the cap in the script protects you.

| | Claude Code | Codex CLI |
| --- | --- | --- |
| Skill folder | `.claude/skills/seedance-batch/` | `.agents/skills/seedance-batch/` |
| Start the skill | `/seedance-batch` | `$seedance-batch` |
| Project instructions | `CLAUDE.md` (reads `AGENTS.md` if there is no `CLAUDE.md`) | `AGENTS.md` |
| Running the script | Permission prompt for each new command | Approval for commands that need the network |
| Stop it starting on its own | `disable-model-invocation: true` | `allow_implicit_invocation: false` |

## Ready-made Seedance skills and MCP servers: read them first

You do not have to write everything yourself. WaveSpeed and BytePlus both publish agent tools. A skill or an MCP server is still code that runs on your computer, so read it before you install it.

> Three ways, published 19 August 2026: a skill with `wavespeed skill install`, which "writes .claude/skills/wavespeed/SKILL.md"; the plugin marketplace with `/plugin marketplace add WaveSpeedAI/claude-plugins`; and an MCP server with `claude mcp add wavespeed -- npx -y @wavespeed/mcp`. The MCP tools include `get_price` and `get_balance`. The key is stored by `wavespeed login`, and the skill "explicitly forbids pasting keys into chat."
>
> — Source: WaveSpeedAI Blog — Use WaveSpeed in Claude Code, read 2026-10-05 — https://wavespeed.ai/blog/ai-workflows/use-wavespeed-in-claude-code/

> `wavespeed skill install` "writes .claude/skills/wavespeed/SKILL.md and .agents/skills/wavespeed/SKILL.md". "Codex reads .agents/skills/, which the same command writes." On prices: ask without the inputs a model bills by "and the formula collapses to the model's base price, which is the floor of its range, not a typical run."
>
> — Source: WaveSpeedAI on GitHub — wavespeed-cli, read 2026-10-05 — https://github.com/WaveSpeedAI/wavespeed-cli

> "We strongly recommend using the Seedance 2.5 Skill to optimize your prompts." Install: `npx --yes skills@latest add "https://arkdocs-en.tos-ap-southeast-1.volces.com/skills/" --skill sd25-pe --yes`. Then "enter /sd25-pe + your prompt to start optimizing the prompt."
>
> — Source: BytePlus ModelArk — Seedance 2.5 prompt guide, read 2026-10-05 — https://docs.byteplus.com/en/docs/ModelArk/2607689

> "Verify you trust each server before connecting it. Servers that fetch external content can expose you to prompt injection risk." Project-scope servers are stored in `.mcp.json` at the project root.
>
> — Source: Claude Code Docs — Connect Claude Code to tools via MCP, read 2026-10-05 — https://code.claude.com/docs/en/mcp

How to judge a Seedance skill from a marketplace:

1. **Who publishes it?** WaveSpeed's skill comes from WaveSpeed, and the `sd25-pe` skill from BytePlus. A skill from an unknown account that asks for its own key sends your prompts and images through someone else's service.
2. **Which key does it want, and where?** A good skill reads it from an environment variable or a login command. A skill that asks you to paste it into a file the agent reads is a risk.
3. **Does it check the price?** The WaveSpeed MCP server has `get_price`. Your skill should tell the agent to use it with the full inputs and to wait for your yes.
4. **What runs on install?** Commands with `--yes` or `-y` skip the confirmation. Open the installed `SKILL.md` and any scripts before the first run.

The WaveSpeed MCP server is the quickest start for single clips. For batches, the script above is easier to control, because the cap is in code you can read.

## What to do with the Seedance clips after the batch

Download every clip at once, keep the files unchanged, and review them yourself before anything is posted. The links do not last.

> "Video URLs are valid for 24 hours. Download or transfer generated videos before the URL expires."
>
> — Source: BytePlus ModelArk — Retrieve a video generation task, read 2026-10-05 — https://docs.byteplus.com/en/docs/ModelArk/get-video-generation-task-api

> "Generated media files are temporary and generally expire within 7 days." "Download immediately — Save outputs you want to keep right after generation".
>
> — Source: WaveSpeedAI docs — Data Retention Policy, read 2026-10-05 — https://wavespeed.ai/docs/data-retention-policy

Then:

1. **Watch every clip in full.** Check the face against your persona, the hands and the last second. The script does not judge quality, and the agent should not either.
2. **Keep the files as they came.** Re-encoding can remove the AI metadata that platforms read. [Do not strip your watermarks](https://aiofmcity.com/blog/dont-strip-your-watermarks-provenance) shows how to check a file.
3. **Label before posting.** A realistic persona clip needs the AI label of each platform you post on.
4. **Post by hand or with the platform's own scheduler.** This setup makes clips. It does not post them, reply to fans or run accounts.

The [AI influencer workflow guide](https://aiofmcity.com/guides/running-an-ai-persona-operation#what-you-can-automate-and-what-you-cannot) explains which steps are safe to automate and which stay with you. If you also want the agent to work in your Fanvue account, [the Fanvue API and MCP server](https://aiofmcity.com/blog/fanvue-api-and-mcp) shows what that connection can do. Start small: put three lines in `jobs.csv`, set `SEEDANCE_MAX_USD` to 5, and run `plan` before you run anything else.

## Frequently asked

### Can Claude Code generate videos with Seedance?

Yes, through a script or an MCP server that calls a Seedance API. Claude does not make the video itself. It writes and runs the code that sends your image and prompt to BytePlus ModelArk or a reseller such as WaveSpeed, waits for the clip and downloads it.

### Does a Claude Code skill also work in Codex?

Yes. Both follow the open Agent Skills standard, and a skill is a folder with a SKILL.md file. Claude Code reads it from .claude/skills, Codex from .agents/skills. Put the folder in one place and link it into the other, or keep two copies.

### How do I stop a Seedance batch from spending too much?

Put the limit in your own script. WaveSpeed documents no usage limit, only a monthly limit for automatic top-ups. Quote every clip with the pricing API first, refuse the batch if the total is over your cap or over your balance, and keep automatic top-up switched off.

### What does one Seedance clip cost through the API?

On 5 October 2026 a 5-second 720p clip cost $0.76 with Seedance 2.0 and $1.156 with Seedance 2.5 on BytePlus ModelArk, for 16:9 and no input video. WaveSpeed listed $1.20 and $1.80 for the same length and resolution.

### Can I use a real person's face in Seedance?

Not directly. BytePlus says the Seedance 2.0 and 2.5 models do not support uploading reference images or videos that contain real human faces, and it offers separate routes for authorised assets. For an AI persona, use only images of your own generated character.

