正在读取公开标价
三步生成第一个视频
标准的 HTTPS 加 JSON 接口,用什么语言都能调用。
创建 API 密钥
在控制台「API 密钥」页创建,存为环境变量
CHENVOYA_API_KEY。提交生成任务
调用
POST /v1/video/generations,立即返回任务 ID 和这次预留的金额。取回视频
查询任务或等回调通知,成功后按返回的下载地址取回视频。
IDEMPOTENCY_KEY=${IDEMPOTENCY_KEY:-$(uuidgen)}
printf '%s\n' "Save IDEMPOTENCY_KEY for retries: ${IDEMPOTENCY_KEY}" >&2
curl --request POST "${CHENVOYA_BASE_URL}/v1/video/generations" \
--header "Authorization: Bearer ${CHENVOYA_API_KEY}" \
--header "Idempotency-Key: ${IDEMPOTENCY_KEY}" \
--header "Content-Type: application/json" \
--data '{
"model": "dreamina-seedance-2-0-260128",
"content": [
{
"type": "text",
"text": "A swordswoman leaps between floating peaks"
}
],
"resolution": "720p",
"ratio": "16:9",
"duration": 10,
"generate_audio": true
}'
import json
import os
import re
import sys
import urllib.request
import uuid
key = os.environ["CHENVOYA_API_KEY"].strip()
if not key or re.search(r"[\x00-\x1f\x7f-\x9f]", key):
sys.exit("Set CHENVOYA_API_KEY to a non-empty value without control characters")
base = os.environ["CHENVOYA_BASE_URL"].rstrip("/")
idempotency = os.environ.get("IDEMPOTENCY_KEY") or str(uuid.uuid4())
print("Save IDEMPOTENCY_KEY for retries: " + idempotency, file=sys.stderr)
body = json.dumps({
"model": "dreamina-seedance-2-0-260128",
"content": [
{
"type": "text",
"text": "A swordswoman leaps between floating peaks",
}
],
"resolution": "720p",
"ratio": "16:9",
"duration": 10,
"generate_audio": True,
}).encode("utf-8")
request = urllib.request.Request(
base + "/v1/video/generations",
data=body,
headers={
"Authorization": "Bearer " + key,
"Idempotency-Key": idempotency,
"Content-Type": "application/json",
},
method="POST",
)
try:
with urllib.request.urlopen(request) as response:
print(response.read().decode("utf-8"))
except urllib.request.HTTPError as error:
print(error.read().decode("utf-8"))
sys.exit(1)
const key = process.env.CHENVOYA_API_KEY?.trim();
if (!key || /[\x00-\x1f\x7f-\x9f]/.test(key)) {
console.error("Set CHENVOYA_API_KEY to a non-empty value without control characters");
process.exit(1);
}
const base = process.env.CHENVOYA_BASE_URL;
if (!base) throw new Error("Set CHENVOYA_BASE_URL");
const idempotency = process.env.IDEMPOTENCY_KEY || crypto.randomUUID();
console.error("Save IDEMPOTENCY_KEY for retries: " + idempotency);
const response = await fetch(base.replace(/\/$/, "") + "/v1/video/generations", {
method: "POST",
headers: {
Authorization: "Bearer " + key,
"Idempotency-Key": idempotency,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "dreamina-seedance-2-0-260128",
content: [
{
type: "text",
text: "A swordswoman leaps between floating peaks",
},
],
resolution: "720p",
ratio: "16:9",
duration: 10,
generate_audio: true,
}),
});
console.log(await response.text());
if (!response.ok) process.exitCode = 1;
package main
import (
"bytes"
"crypto/rand"
"fmt"
"io"
"net/http"
"os"
"regexp"
"strings"
)
func main() {
key := strings.TrimSpace(os.Getenv("CHENVOYA_API_KEY"))
if key == "" || regexp.MustCompile(`[\x00-\x1f\x7f-\x9f]`).MatchString(key) {
fmt.Fprintln(os.Stderr, "Set CHENVOYA_API_KEY to a non-empty value without control characters")
os.Exit(1)
}
base := strings.TrimRight(os.Getenv("CHENVOYA_BASE_URL"), "/")
idempotency := os.Getenv("IDEMPOTENCY_KEY")
if idempotency == "" {
id := make([]byte, 16)
if _, err := rand.Read(id); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
id[6], id[8] = id[6]&0x0f|0x40, id[8]&0x3f|0x80
idempotency = fmt.Sprintf("%x-%x-%x-%x-%x", id[0:4], id[4:6], id[6:8], id[8:10], id[10:])
}
fmt.Fprintln(os.Stderr, "Save IDEMPOTENCY_KEY for retries: "+idempotency)
body := []byte(`{
"model": "dreamina-seedance-2-0-260128",
"content": [
{
"type": "text",
"text": "A swordswoman leaps between floating peaks"
}
],
"resolution": "720p",
"ratio": "16:9",
"duration": 10,
"generate_audio": true
}`)
request, err := http.NewRequest("POST", base+"/v1/video/generations", bytes.NewReader(body))
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
request.Header.Set("Authorization", "Bearer "+key)
request.Header.Set("Idempotency-Key", idempotency)
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
reply, err := io.ReadAll(response.Body)
response.Body.Close()
fmt.Println(string(reply))
if err != nil || response.StatusCode >= 300 {
os.Exit(1)
}
}
费用、来源和回调,每一笔都查得到
控制台按任务记下预留与结算、调用来源和每一次回调投递。下面是控制台里的样子。
按实际用量结算,失败和取消不收费
创建任务时按参数预留费用,完成后按实际视频 token 结算;任务失败,或在生成开始前取消,预留全部释放。
一个 API 密钥调用全部模型
三个模型共用同一个 API 密钥和同一套参数,换模型只需改 model 字段。
任务与回调记录可查
每个任务的状态、费用和回调投递都能在控制台查到;回调没有送达会自动重试,最长七天。
常见问题
怎么计费?
视频按实际交付视频的 token 计费,单价见价格页。提交任务时先预留费用,任务结束后按实际用量结算,多余部分退回。金额以美元计,费率保留完整精度。
失败或取消的任务收费吗?
不收费。创建任务时先预留费用;生成失败,或在生成开始前取消,预留的金额会全部释放。生成开始后取消不生效,成功仍照常收费。
网络超时后重试,会重复收费吗?
不会。用原请求体和同一个已保存的 Idempotency-Key 重发,拿到的是同一个任务,不会重复预留,也不会重复收费;重试时不要生成新的值。
怎样拿到生成结果?
查询任务状态;或先在控制台登记并验证 HTTPS 回调地址,创建任务时传 callback_url,任务完成后会收到 task.completed 通知。
开始生成第一个视频
账户开通后,在控制台创建 API 密钥,几分钟就能跑通第一个请求。


