@acedatacloud/skills 2026.628.6 → 2026.629.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acedatacloud/skills",
3
- "version": "2026.628.6",
3
+ "version": "2026.629.0",
4
4
  "description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -5,8 +5,11 @@ description: |
5
5
  (platform.acedata.cloud). Use when the user wants to check their balance /
6
6
  remaining credits, look up API call (usage) records and spend, list or create
7
7
  or delete API keys (credentials), list subscribed services, list/create/pay
8
- recharge orders, manage platform tokens, list available models, or (admins)
9
- publish an announcement. This is the self-service "console" API distinct
8
+ recharge orders, manage platform tokens, view referral/affiliate earnings, or
9
+ (admins) publish an announcement. Also covers the PUBLIC catalog & docs (no
10
+ token needed): service detail & pricing, API list & OpenAPI specs, datasets,
11
+ integrations, full-text documentation search, and the model catalog with
12
+ per-model credit pricing. This is the self-service "console" API — distinct
10
13
  from the data-generation APIs (image/video/music/search).
11
14
  license: Apache-2.0
12
15
  metadata:
@@ -19,7 +22,9 @@ compatibility: Requires ACEDATACLOUD_PLATFORM_TOKEN (a platform or user token).
19
22
  # AceDataCloud Platform Management
20
23
 
21
24
  Programmatically manage your AceDataCloud account: balances, usage records, API
22
- keys, services, orders, platform tokens, models, and announcements.
25
+ keys, services, orders, platform tokens, models, announcements and referral
26
+ earnings — plus browse the public catalog & docs (service pricing, API specs,
27
+ datasets, integrations, documentation search, model catalog) without a token.
23
28
 
24
29
  This is the **management / console** API at `https://platform.acedata.cloud/api/v1`
25
30
  — the same surface the web console uses. It is **different** from the
@@ -68,6 +73,20 @@ python3 $ADC keys # list API keys (credentials)
68
73
  python3 $ADC orders --state Finished # recharge orders
69
74
  python3 $ADC tokens # platform tokens
70
75
  python3 $ADC models # available chat models
76
+ python3 $ADC distributions # referral status + commission history
77
+
78
+ # Catalog & docs (PUBLIC — work without a token)
79
+ python3 $ADC get-service --service suno # one service's detail
80
+ python3 $ADC pricing --service suno # unit, free_amount and cost
81
+ python3 $ADC apis --service suno # API endpoints for a service
82
+ python3 $ADC spec --path /suno/audios # one API's OpenAPI definition + cost
83
+ python3 $ADC datasets # downloadable datasets
84
+ python3 $ADC integrations # third-party integrations
85
+ python3 $ADC docs-search --query "suno lyrics" --lang en # full-text doc search
86
+ python3 $ADC docs-list # browse documentation pages
87
+ python3 $ADC doc --id <document-uuid> # one doc's full content
88
+ python3 $ADC model-catalog --modality chat # rich model catalog + credit pricing
89
+ python3 $ADC model --model claude # look up a model by id/name
71
90
 
72
91
  # Safe write (require --yes to actually execute)
73
92
  python3 $ADC create-key --application <app-id> --name "ci" --yes
@@ -206,6 +225,22 @@ Filters: `api_id`, `application_id`, `status_code`, `created_at_from`,
206
225
  OpenAI-style (no pagination): `{ "object": "list", "data": [ { "id": "gpt-4.1",
207
226
  "label": "GPT-4.1", "owned_by": "openai", "type": "chat", "capabilities": ["vision"] } ] }`
208
227
 
228
+ ### Catalog & docs (PUBLIC — no token required)
229
+
230
+ These work without auth (send the token if you have one; not required):
231
+
232
+ - **Service detail / pricing** — `GET /services/?id=<uuid>` → `items[0]` (full: `cost`, `unit`,
233
+ `free_amount`, `title`). The `services/?alias=` filter is **ignored** server-side, so resolve an
234
+ alias by paging `services/` and matching `alias` client-side. The `services/{id}/` detail route is broken (500).
235
+ - **APIs** — `GET /apis/?path=<path>` → exactly one item with its OpenAPI `definition` + `cost`.
236
+ `apis/?service_id=` is **ignored** server-side; filter by `service_id` client-side. `apis/{id}/` is broken (500).
237
+ - **Datasets / integrations** — `GET /datasets/`, `GET /integrations/`.
238
+ - **Doc search** — `GET /search/?query=<text>&lang=<code>` → `{ results: [ { id, alias, title, type, snippet, url } ] }`.
239
+ The param is **`query`** (not `keyword`).
240
+ - **Doc content** — `GET /documents/?id=<uuid>` → `items[0].content`. `documents/{id}/` (id or slug) is broken (404).
241
+ - **Model catalog** — `GET /models/catalog/` → `{ rates, modalities, count, items:[{ id, name, provider,
242
+ modality, unit, capabilities, pricing:{ input_credits, output_credits, official_* } }] }`. Filter client-side.
243
+
209
244
  ### Announcements — `GET /announcements/`
210
245
 
211
246
  Public read: `{ "count": 20, "items": [ { "id", "title", "content",
@@ -241,4 +276,4 @@ publishing announcements are **irreversible or money-related**. Always:
241
276
  - Announcement endpoints under `/admin/` require a **superuser** token; a normal
242
277
  token gets `403`.
243
278
 
244
- > **MCP:** `pip install mcp-acedatacloud` | See [all MCP servers](../_shared/mcp-servers.md). The MCP exposes these as tools (`platform_get_balance`, `platform_list_usage`, `platform_create_credential`, `platform_create_announcement`, …) with the same write-confirmation guard.
279
+ > **MCP:** `pip install mcp-acedatacloud` | Hosted: `https://mcp.acedata.cloud/mcp` | See [all MCP servers](../_shared/mcp-servers.md). The MCP exposes these as tools (`acedatacloud_get_balance`, `acedatacloud_list_usage`, `acedatacloud_get_pricing`, `acedatacloud_search_docs`, `acedatacloud_get_api_spec`, `acedatacloud_create_credential`, …) with the same write-confirmation guard.
@@ -18,6 +18,7 @@ import argparse
18
18
  import datetime as dt
19
19
  import json
20
20
  import os
21
+ import re
21
22
  import sys
22
23
  import urllib.error
23
24
  import urllib.parse
@@ -32,18 +33,9 @@ def _die(msg: str, code: int = 1) -> None:
32
33
  sys.exit(code)
33
34
 
34
35
 
35
- def _token(args: argparse.Namespace) -> str:
36
- token = args.token or os.environ.get("ACEDATACLOUD_PLATFORM_TOKEN", "")
37
- if not token:
38
- _die(
39
- "no platform token. Set ACEDATACLOUD_PLATFORM_TOKEN or pass --token.\n"
40
- "Create one at https://platform.acedata.cloud/console/platform-tokens"
41
- )
42
- return token
43
-
44
-
45
36
  def _request(args: argparse.Namespace, method: str, path: str,
46
- params: dict | None = None, body: dict | None = None) -> tuple[int, object]:
37
+ params: dict | None = None, body: dict | None = None,
38
+ auth_required: bool = True) -> tuple[int, object]:
47
39
  base = args.base_url.rstrip("/")
48
40
  url = f"{base}/api/v1{path}"
49
41
  if params:
@@ -51,11 +43,16 @@ def _request(args: argparse.Namespace, method: str, path: str,
51
43
  if clean:
52
44
  url += "?" + urllib.parse.urlencode(clean, doseq=True)
53
45
  data = json.dumps(body).encode() if body is not None else None
54
- req = urllib.request.Request(url, data=data, method=method, headers={
55
- "accept": "application/json",
56
- "authorization": f"Bearer {_token(args)}",
57
- "content-type": "application/json",
58
- })
46
+ headers = {"accept": "application/json", "content-type": "application/json"}
47
+ token = args.token or os.environ.get("ACEDATACLOUD_PLATFORM_TOKEN", "")
48
+ if token:
49
+ headers["authorization"] = f"Bearer {token}"
50
+ elif auth_required:
51
+ _die(
52
+ "no platform token. Set ACEDATACLOUD_PLATFORM_TOKEN or pass --token.\n"
53
+ "Create one at https://platform.acedata.cloud/console/platform-tokens"
54
+ )
55
+ req = urllib.request.Request(url, data=data, method=method, headers=headers)
59
56
  try:
60
57
  with urllib.request.urlopen(req, timeout=args.timeout) as resp:
61
58
  raw = resp.read().decode("utf-8")
@@ -72,7 +69,7 @@ def _request(args: argparse.Namespace, method: str, path: str,
72
69
 
73
70
 
74
71
  def _get_all(args: argparse.Namespace, path: str, params: dict | None = None,
75
- page: int = 200, cap: int = 2000) -> tuple[int, list]:
72
+ page: int = 200, cap: int = 2000, auth_required: bool = True) -> tuple[int, list]:
76
73
  """Fetch every page of a {count, items} list endpoint (capped)."""
77
74
  base = dict(params or {})
78
75
  out: list = []
@@ -80,7 +77,7 @@ def _get_all(args: argparse.Namespace, path: str, params: dict | None = None,
80
77
  total = 0
81
78
  while len(out) < cap:
82
79
  base.update({"limit": page, "offset": offset})
83
- status, payload = _request(args, "GET", path, base)
80
+ status, payload = _request(args, "GET", path, base, auth_required=auth_required)
84
81
  _check_ok(status, payload)
85
82
  items = payload.get("items", []) if isinstance(payload, dict) else []
86
83
  total = payload.get("count", 0) if isinstance(payload, dict) else 0
@@ -142,6 +139,29 @@ def _since(days: int | None) -> str | None:
142
139
  return (dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=days)).strftime("%Y-%m-%dT%H:%M:%SZ")
143
140
 
144
141
 
142
+ _UUID = re.compile(r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
143
+
144
+
145
+ def _resolve_service(args, ref: str) -> dict | None:
146
+ """Resolve a service by UUID (services/?id=) or alias (paginated match).
147
+
148
+ The platform's services/?alias= filter is ignored server-side, so alias
149
+ lookups page through the catalog and match client-side.
150
+ """
151
+ ref = ref.strip()
152
+ if _UUID.match(ref):
153
+ status, payload = _request(args, "GET", "/services/", {"id": ref}, auth_required=False)
154
+ _check_ok(status, payload)
155
+ items = payload.get("items", []) if isinstance(payload, dict) else []
156
+ return items[0] if items else None
157
+ target = ref.lower()
158
+ _, items = _get_all(args, "/services/", page=50, cap=600, auth_required=False)
159
+ for it in items:
160
+ if (it.get("alias") or "").lower() == target:
161
+ return it
162
+ return None
163
+
164
+
145
165
  # ---- read commands -------------------------------------------------------
146
166
 
147
167
  def cmd_balance(args):
@@ -261,6 +281,179 @@ def cmd_announcements(args):
261
281
  _emit(args, payload, rows, ("id", "title", "rank", "publish_at"))
262
282
 
263
283
 
284
+ # ---- catalog & docs commands (public, no token needed) ------------------
285
+
286
+ def cmd_get_service(args):
287
+ svc = _resolve_service(args, args.service)
288
+ if not svc:
289
+ _die(f"no service matched '{args.service}'", code=2)
290
+ _emit(args, svc)
291
+
292
+
293
+ def cmd_pricing(args):
294
+ svc = _resolve_service(args, args.service)
295
+ if not svc:
296
+ _die(f"no service matched '{args.service}'", code=2)
297
+ out = {
298
+ "service_id": svc.get("id"),
299
+ "alias": svc.get("alias"),
300
+ "title": svc.get("title"),
301
+ "type": svc.get("type"),
302
+ "unit": svc.get("unit"),
303
+ "free_amount": svc.get("free_amount"),
304
+ "cost": svc.get("cost"),
305
+ }
306
+ _emit(args, out)
307
+
308
+
309
+ def cmd_apis(args):
310
+ sid = None
311
+ if args.service:
312
+ svc = _resolve_service(args, args.service)
313
+ if not svc:
314
+ _die(f"no service matched '{args.service}'", code=2)
315
+ sid = svc.get("id")
316
+ # apis/?service_id= is ignored server-side, so filter client-side.
317
+ _, items = _get_all(args, "/apis/", page=50, cap=2000, auth_required=False)
318
+ if sid:
319
+ items = [it for it in items if it.get("service_id") == sid]
320
+ items = items[: args.limit]
321
+ slim = [{k: v for k, v in it.items() if k != "definition"} for it in items]
322
+ rows = [(
323
+ (it.get("path") or ""),
324
+ it.get("method"),
325
+ it.get("stage"),
326
+ (it.get("title") or "")[:30],
327
+ ) for it in items]
328
+ _emit(args, {"count": len(slim), "items": slim}, rows, ("path", "method", "stage", "title"))
329
+
330
+
331
+ def cmd_spec(args):
332
+ status, payload = _request(args, "GET", "/apis/", {"path": args.path}, auth_required=False)
333
+ _check_ok(status, payload)
334
+ items = payload.get("items", []) if isinstance(payload, dict) else []
335
+ if not items:
336
+ _die(f"no API matched path '{args.path}'", code=2)
337
+ api = items[0]
338
+ _emit(args, {
339
+ "id": api.get("id"),
340
+ "service_id": api.get("service_id"),
341
+ "title": api.get("title"),
342
+ "path": api.get("path"),
343
+ "method": api.get("method"),
344
+ "stage": api.get("stage"),
345
+ "cost": api.get("cost"),
346
+ "definition": api.get("definition"),
347
+ })
348
+
349
+
350
+ def cmd_datasets(args):
351
+ status, payload = _request(args, "GET", "/datasets/", {"limit": args.limit}, auth_required=False)
352
+ _check_ok(status, payload)
353
+ items = payload.get("items", []) if isinstance(payload, dict) else []
354
+ rows = [(it.get("id", "")[:8], (it.get("title") or "")[:30], it.get("price"), (it.get("part") or "")) for it in items]
355
+ _emit(args, payload, rows, ("id", "title", "price", "part"))
356
+
357
+
358
+ def cmd_integrations(args):
359
+ status, payload = _request(args, "GET", "/integrations/", {"limit": args.limit}, auth_required=False)
360
+ _check_ok(status, payload)
361
+ items = payload.get("items", []) if isinstance(payload, dict) else []
362
+ rows = [(it.get("id", "")[:8], (it.get("title") or "")[:34], it.get("stage")) for it in items]
363
+ _emit(args, payload, rows, ("id", "title", "stage"))
364
+
365
+
366
+ def cmd_docs_search(args):
367
+ status, payload = _request(args, "GET", "/search/", {"query": args.query, "lang": args.lang}, auth_required=False)
368
+ _check_ok(status, payload)
369
+ results = payload.get("results", []) if isinstance(payload, dict) else []
370
+ rows = [((r.get("title") or "")[:44], r.get("type"), r.get("matched_lang"), (r.get("id") or "")[:8]) for r in results]
371
+ _emit(args, payload, rows, ("title", "type", "lang", "id"))
372
+
373
+
374
+ def cmd_docs_list(args):
375
+ status, payload = _request(args, "GET", "/documents/", {"limit": args.limit, "type": args.type}, auth_required=False)
376
+ _check_ok(status, payload)
377
+ items = payload.get("items", []) if isinstance(payload, dict) else []
378
+ rows = [(it.get("id", "")[:8], (it.get("title") or "")[:40], it.get("type"), it.get("alias")) for it in items]
379
+ _emit(args, {"count": payload.get("count") if isinstance(payload, dict) else None, "items": items}, rows,
380
+ ("id", "title", "type", "alias"))
381
+
382
+
383
+ def cmd_doc(args):
384
+ if not _UUID.match(args.id.strip()):
385
+ _die("doc id must be a document UUID", code=2)
386
+ status, payload = _request(args, "GET", "/documents/", {"id": args.id.strip()}, auth_required=False)
387
+ _check_ok(status, payload)
388
+ items = payload.get("items", []) if isinstance(payload, dict) else []
389
+ if not items:
390
+ _die(f"no document with id '{args.id}'", code=2)
391
+ _emit(args, items[0])
392
+
393
+
394
+ def cmd_model_catalog(args):
395
+ status, payload = _request(args, "GET", "/models/catalog/", auth_required=False)
396
+ _check_ok(status, payload)
397
+ items = payload.get("items", []) if isinstance(payload, dict) else []
398
+ if args.modality:
399
+ m = args.modality.lower()
400
+ items = [it for it in items if (it.get("modality") or "").lower() == m]
401
+ if args.provider:
402
+ pv = args.provider.lower()
403
+ items = [it for it in items if pv in (it.get("provider") or "").lower()]
404
+ rows = [(
405
+ it.get("id"),
406
+ it.get("provider"),
407
+ it.get("modality"),
408
+ (it.get("pricing") or {}).get("input_credits"),
409
+ (it.get("pricing") or {}).get("output_credits"),
410
+ ) for it in items]
411
+ out = {"modalities": payload.get("modalities") if isinstance(payload, dict) else None,
412
+ "count": len(items), "items": items}
413
+ _emit(args, out, rows, ("id", "provider", "modality", "in_credits", "out_credits"))
414
+
415
+
416
+ def cmd_model(args):
417
+ status, payload = _request(args, "GET", "/models/catalog/", auth_required=False)
418
+ _check_ok(status, payload)
419
+ q = args.model.strip().lower()
420
+ items = [it for it in (payload.get("items", []) if isinstance(payload, dict) else [])
421
+ if q in (it.get("id") or "").lower() or q in (it.get("name") or "").lower()]
422
+ if not items:
423
+ _die(f"no model matched '{args.model}'", code=2)
424
+ rows = [(
425
+ it.get("id"),
426
+ it.get("provider"),
427
+ it.get("modality"),
428
+ (it.get("pricing") or {}).get("input_credits"),
429
+ (it.get("pricing") or {}).get("output_credits"),
430
+ ) for it in items]
431
+ _emit(args, {"count": len(items), "items": items}, rows,
432
+ ("id", "provider", "modality", "in_credits", "out_credits"))
433
+
434
+
435
+ def cmd_distributions(args):
436
+ status, status_payload = _request(args, "GET", "/distribution-statuses/", {"limit": 1})
437
+ _check_ok(status, status_payload)
438
+ st_items = status_payload.get("items", []) if isinstance(status_payload, dict) else []
439
+ hstatus, hist = _request(args, "GET", "/distribution-histories/", {"limit": args.limit})
440
+ _check_ok(hstatus, hist)
441
+ hitems = hist.get("items", []) if isinstance(hist, dict) else []
442
+ out = {
443
+ "status": st_items[0] if st_items else None,
444
+ "history_count": hist.get("count") if isinstance(hist, dict) else None,
445
+ "history": hitems,
446
+ }
447
+ rows = [(
448
+ (it.get("created_at") or "")[:10],
449
+ it.get("price"),
450
+ it.get("reward"),
451
+ it.get("percentage"),
452
+ "invalid" if it.get("invalid") else "ok",
453
+ ) for it in hitems]
454
+ _emit(args, out, rows, ("date", "price", "reward", "pct", "state"))
455
+
456
+
264
457
  # ---- write commands (gated by --yes) -------------------------------------
265
458
 
266
459
  def _guard(args, action: str, detail: dict) -> bool:
@@ -405,6 +598,47 @@ def build_parser() -> argparse.ArgumentParser:
405
598
  sp = add("announcements", cmd_announcements, "list announcements")
406
599
  sp.add_argument("--limit", type=int, default=20)
407
600
 
601
+ sp = add("distributions", cmd_distributions, "referral status + commission history")
602
+ sp.add_argument("--limit", type=int, default=20)
603
+
604
+ # ---- catalog & docs (public, no token needed) ----
605
+ sp = add("get-service", cmd_get_service, "one service's detail by alias or id")
606
+ sp.add_argument("--service", required=True, help="service alias or UUID")
607
+
608
+ sp = add("pricing", cmd_pricing, "a service's unit, free_amount and cost")
609
+ sp.add_argument("--service", required=True, help="service alias or UUID")
610
+
611
+ sp = add("apis", cmd_apis, "list API endpoints (optionally per service)")
612
+ sp.add_argument("--service", help="scope to a service alias or UUID")
613
+ sp.add_argument("--limit", type=int, default=50)
614
+
615
+ sp = add("spec", cmd_spec, "one API's OpenAPI definition + cost, by path")
616
+ sp.add_argument("--path", required=True, help="API path, e.g. /suno/audios")
617
+
618
+ sp = add("datasets", cmd_datasets, "list downloadable datasets")
619
+ sp.add_argument("--limit", type=int, default=50)
620
+
621
+ sp = add("integrations", cmd_integrations, "list third-party integrations")
622
+ sp.add_argument("--limit", type=int, default=50)
623
+
624
+ sp = add("docs-search", cmd_docs_search, "full-text search the documentation")
625
+ sp.add_argument("--query", required=True)
626
+ sp.add_argument("--lang", help="language code, e.g. en, zh-cn")
627
+
628
+ sp = add("docs-list", cmd_docs_list, "browse documentation pages")
629
+ sp.add_argument("--limit", type=int, default=30)
630
+ sp.add_argument("--type", help="document type filter, e.g. Text")
631
+
632
+ sp = add("doc", cmd_doc, "fetch one doc's full content by UUID")
633
+ sp.add_argument("--id", required=True, help="document UUID")
634
+
635
+ sp = add("model-catalog", cmd_model_catalog, "rich model catalog with credit pricing")
636
+ sp.add_argument("--modality", help="chat/video/image/music/search/embedding")
637
+ sp.add_argument("--provider", help="filter by provider substring")
638
+
639
+ sp = add("model", cmd_model, "look up a model by id/name")
640
+ sp.add_argument("--model", required=True)
641
+
408
642
  sp = add("create-key", cmd_create_key, "create an API key (needs --yes)")
409
643
  sp.add_argument("--application", required=True)
410
644
  sp.add_argument("--name")
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: seedance-video
3
- description: Generate AI dance and motion videos with Seedance (ByteDance) via AceDataCloud API. Use when creating videos from text prompts or animating images into motion videos. Supports multiple models with configurable resolution, aspect ratio, duration, and optional audio generation.
3
+ description: Generate AI videos with Seedance (ByteDance) via AceDataCloud API. Use when creating videos from text prompts, animating images into motion videos, or driving Seedance 2.0 multimodal generation with real-person / character image references, reference audio, and reference video. Supports multiple models with configurable resolution (up to 4k), aspect ratio, duration, and optional audio generation.
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: acedatacloud
@@ -20,7 +20,7 @@ Generate AI dance and motion videos through AceDataCloud's Seedance (ByteDance)
20
20
  curl -X POST https://api.acedata.cloud/seedance/videos \
21
21
  -H "Authorization: Bearer $ACEDATACLOUD_API_TOKEN" \
22
22
  -H "Content-Type: application/json" \
23
- -d '{"model": "doubao-seedance-1-0-pro-250528", "content": [{"type": "text", "text": "a dancer performing contemporary ballet in a misty forest"}], "callback_url": "https://api.acedata.cloud/health"}'
23
+ -d '{"model": "doubao-seedance-2-0-260128", "content": [{"type": "text", "text": "a dancer performing contemporary ballet in a misty forest"}], "callback_url": "https://api.acedata.cloud/health"}'
24
24
  ```
25
25
 
26
26
  > **Async:** See [async task polling](../_shared/async-tasks.md). Poll via `POST /seedance/tasks` with `{"id": "..."}`.
@@ -35,11 +35,23 @@ curl -X POST https://api.acedata.cloud/seedance/tasks \
35
35
 
36
36
  ## Models
37
37
 
38
+ ### Seedance 2.0 (current generation — multimodal reference)
39
+
40
+ The 2.0 series adds multimodal reference inputs: real-person / character **image** references, reference **audio**, and reference **video** (see the workflows below).
41
+
42
+ | Model | Best For | Max resolution |
43
+ |-------|----------|----------------|
44
+ | `doubao-seedance-2-0-260128` | Highest quality, real-person/character reference, 4k output | `4k` |
45
+ | `doubao-seedance-2-0-fast-260128` | Faster 2.0 generation | `720p` |
46
+ | `doubao-seedance-2-0-mini-260615` | Lightweight / most cost-effective 2.0 | `720p` |
47
+
48
+ ### Seedance 1.x
49
+
38
50
  | Model | Type | Best For |
39
51
  |-------|------|----------|
52
+ | `doubao-seedance-1-5-pro-251215` | Text+Image-to-Video | 1.5 flagship, audio support |
40
53
  | `doubao-seedance-1-0-pro-250528` | Text+Image-to-Video | General-purpose, reliable quality |
41
54
  | `doubao-seedance-1-0-pro-fast-251015` | Text+Image-to-Video | Faster Pro generation |
42
- | `doubao-seedance-1-5-pro-251215` | Text+Image-to-Video | Latest model, highest quality, audio support |
43
55
  | `doubao-seedance-1-0-lite-t2v-250428` | Text-to-Video only | Lightweight text-to-video |
44
56
  | `doubao-seedance-1-0-lite-i2v-250428` | Image-to-Video only | Lightweight image-to-video |
45
57
 
@@ -86,7 +98,11 @@ POST /seedance/videos
86
98
  Image roles:
87
99
  - `first_frame` — image is used as the opening frame
88
100
  - `last_frame` — image is used as the closing frame
89
- - `reference_image` — image is used as a style/content reference
101
+ - `reference_image` — image is used as a style / subject / real-person reference (Seedance 2.0 keeps the referenced person or character consistent)
102
+
103
+ Reference media (Seedance 2.0 only):
104
+ - `audio_url` — reference audio for voice timbre / background music (no `role`)
105
+ - `video_url` — reference video for subject, camera movement, motion or overall style (no `role`)
90
106
 
91
107
  ### 3. First-frame + Last-frame
92
108
 
@@ -95,7 +111,7 @@ Provide both a start and end frame image:
95
111
  ```json
96
112
  POST /seedance/videos
97
113
  {
98
- "model": "doubao-seedance-1-0-pro-250528",
114
+ "model": "doubao-seedance-2-0-260128",
99
115
  "content": [
100
116
  {"type": "text", "text": "smooth transition between two scenes"},
101
117
  {"type": "image_url", "role": "first_frame", "image_url": {"url": "https://example.com/start.jpg"}},
@@ -104,18 +120,53 @@ POST /seedance/videos
104
120
  }
105
121
  ```
106
122
 
123
+ ### 4. Real-person / character reference (Seedance 2.0)
124
+
125
+ Seedance 2.0 models (`doubao-seedance-2-0-260128`, `doubao-seedance-2-0-fast-260128`, `doubao-seedance-2-0-mini-260615`) can keep a **specific person or character** consistent across a brand-new scene. Pass one or more photos as `image_url` items with `role: "reference_image"` — the model preserves that subject's appearance. Up to 9 reference images are accepted.
126
+
127
+ ```json
128
+ POST /seedance/videos
129
+ {
130
+ "model": "doubao-seedance-2-0-260128",
131
+ "content": [
132
+ {"type": "text", "text": "the same person walking through a neon-lit night market, cinematic"},
133
+ {"type": "image_url", "role": "reference_image", "image_url": {"url": "https://example.com/person.jpg"}}
134
+ ],
135
+ "resolution": "1080p",
136
+ "duration": 8
137
+ }
138
+ ```
139
+
140
+ ### 5. Reference audio / video (Seedance 2.0)
141
+
142
+ 2.0 models also accept reference **audio** (voice timbre, background music) and reference **video** (subject content, camera movement, motion, overall style). Add `audio_url` and/or `video_url` content items. Limits: up to 3 audio and 3 video references per request.
143
+
144
+ ```json
145
+ POST /seedance/videos
146
+ {
147
+ "model": "doubao-seedance-2-0-260128",
148
+ "content": [
149
+ {"type": "text", "text": "a singer performing on stage, matching the reference voice and motion"},
150
+ {"type": "image_url", "role": "reference_image", "image_url": {"url": "https://example.com/person.jpg"}},
151
+ {"type": "audio_url", "audio_url": {"url": "https://example.com/voice.mp3"}},
152
+ {"type": "video_url", "video_url": {"url": "https://example.com/motion.mp4"}}
153
+ ],
154
+ "generate_audio": true
155
+ }
156
+ ```
157
+
107
158
  ## Parameters
108
159
 
109
160
  | Parameter | Values | Description |
110
161
  |-----------|--------|-------------|
111
162
  | `model` | see Models table | Model to use (required) |
112
- | `content` | array | Input items: text and/or image_url objects (required) |
113
- | `resolution` | `"480p"`, `"720p"`, `"1080p"` | Output resolution (default: 720p for pro, 480p for lite) |
163
+ | `content` | array | Input items: `text`, `image_url`, `audio_url` (2.0), `video_url` (2.0) (required) |
164
+ | `resolution` | `"480p"`, `"720p"`, `"1080p"`, `"4k"` | Output resolution. `4k` is `doubao-seedance-2-0-260128` (standard) only; `2-0-fast` / `2-0-mini` max out at `720p` (default: 720p for pro/2.0, 480p for lite) |
114
165
  | `ratio` | `"16:9"`, `"4:3"`, `"1:1"`, `"3:4"`, `"9:16"`, `"21:9"`, `"adaptive"` | Aspect ratio (default: 16:9) |
115
- | `duration` | `2` – `12` | Duration in seconds |
116
- | `frames` | 29–289 (must satisfy 25+4n) | Frame count — mutually exclusive with `duration` |
166
+ | `duration` | `2` – `15` | Duration in seconds (Seedance 2.0 supports 4–15) |
167
+ | `frames` | 29–361 (must satisfy 25+4n) | Frame count — mutually exclusive with `duration` |
117
168
  | `seed` | -1 to 4294967295 | Seed for reproducible results (-1 = random) |
118
- | `generate_audio` | `true` / `false` | Generate audio (only supported by `doubao-seedance-1-5-pro-251215`) |
169
+ | `generate_audio` | `true` / `false` | Generate audio (supported by `doubao-seedance-1-5-pro-251215` and the `doubao-seedance-2-0` series; other models ignore it) |
119
170
  | `camerafixed` | `true` / `false` | Fix the camera position during generation |
120
171
  | `watermark` | `true` / `false` | Add a watermark to the generated video |
121
172
  | `return_last_frame` | `true` / `false` | Return the last frame of the generated video |
@@ -137,12 +188,13 @@ Supported inline params: `--rs` (resolution), `--rt` (ratio), `--dur` (duration)
137
188
  - Model names use the `doubao-*` convention (e.g. `doubao-seedance-1-0-pro-250528`) — old short names like `seedance-1.0` are not valid
138
189
  - The `content` array replaces the old `prompt` + `image_url` fields; always use `content`
139
190
  - Image and text scenarios are mutually exclusive per content item — each item has either `text` or `image_url`, not both
140
- - `first_frame`, `last_frame`, and `reference_image` roles are mutually exclusive scenariospick one pattern per request
141
- - `generate_audio: true` is only supported by `doubao-seedance-1-5-pro-251215`; other models ignore this field
191
+ - `first_frame` and `last_frame` may be combined in one request, but `reference_image` is mutually exclusive with `first_frame` / `last_frame` do not mix a reference image with first/last frames
192
+ - `generate_audio: true` is supported by `doubao-seedance-1-5-pro-251215` and the `doubao-seedance-2-0` series; other models ignore this field
142
193
  - Lite models are split: `*-lite-t2v-*` only accepts text, `*-lite-i2v-*` only accepts image-to-video
143
- - Resolution options are `480p`, `720p`, `1080p` there is no 360p or 540p
194
+ - `audio_url` and `video_url` reference items are used by the **Seedance 2.0 series only**
195
+ - Resolution options are `480p`, `720p`, `1080p`, and `4k` (`4k` is `doubao-seedance-2-0-260128` only; `2-0-fast` / `2-0-mini` max out at `720p`) — there is no 360p or 540p
144
196
  - `service_tier` values are `"default"` and `"flex"` (not "standard"/"premium")
145
- - Duration range is **2–12 seconds** — values outside this range will fail
197
+ - Duration range is **2–15 seconds** (Seedance 2.0 supports 4–15) — values outside this range will fail
146
198
  - Task states use `"succeeded"` (not "completed") — check for this value when polling
147
199
 
148
200
  > **MCP:** `pip install mcp-seedance` | Hosted: `https://seedance.mcp.acedata.cloud/mcp` | See [all MCP servers](../_shared/mcp-servers.md)