官方 SDK 快速上手
官方 SDK 封装一步式契约(提交 → 轮询 → 下载),自动幂等键与类型化错误;Node 零依赖,Python 仅依赖 httpx。当前为 GitHub 仓库形态,npm/PyPI 正式发布另行公告。
Node
npm install github:openaiav/sdk-node # npm 正式发布另行公告
import { OpenAiav } from '@openaiav/sdk'
const client = new OpenAiav({ apiKey: process.env.OPENAIAV_API_KEY })
const task = await client.generations.createAndWait({
model: 'seedance-2.5-oa', prompt: 'She walks into the sunlight.',
resolution: '480p', aspectRatio: 'adaptive', durationSeconds: 4,
generateAudio: false
})
await client.generations.downloadToFile(task.id, './out.mp4')Python
pip install git+https://github.com/openaiav/sdk-python # PyPI 正式发布另行公告
from openaiav import OpenAiav
client = OpenAiav(os.environ["OPENAIAV_API_KEY"])
task = client.generations.create_and_wait({
"model": "seedance-2.5-oa", "prompt": "She walks into the sunlight.",
"resolution": "480p", "aspectRatio": "adaptive", "durationSeconds": 4,
"generateAudio": False,
})
client.generations.download_to_file(task["id"], "./out.mp4")四步接入
- 使用服务端环境变量 OPENAIAV_API_KEY 调用 https://api.openaiav.com/v1/models,读取当前模型键、计价与 reference_modes。
- 向 POST /v1/generations 提交 prompt、referenceMode 与 referenceImages;参考图是公网 HTTPS URL,不需要预注册。创建成功为 HTTP 201。
- 保存响应 id,按 poll_after_ms 对同一个 GET /v1/generations/{id} 轮询。processing、result_pending、submission_unknown 都继续等待,不要重新创建。
- 状态变为 succeeded 后调用 GET /v1/generations/{id}/content 下载;完整响应为 HTTP 200,单区间 Range 为 206。
认证与幂等
export OPENAIAV_API_KEY='oav_...'
export OPENAIAV_IDEMPOTENCY_KEY='openaiav-quickstart-4s-480p-001'每个请求都带 Authorization: Bearer oav_...。密钥只放在服务端。创建任务需要 generation:create,查询和下载需要 generation:read。网络结果不确定时复用原 Idempotency-Key;同一个键不得配不同请求体。
请求头
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| Authorization | string | 必填 | 所有 /v1 请求均使用 Bearer oav_...;密钥只保存在服务端。 |
| Idempotency-Key | string | 仅创建任务必填 | 网络重试必须复用同一个值;同值同请求体不会重复生成或重复扣费。 |
| Content-Type | string | 仅 POST 必填 | 创建任务使用 application/json。 |
端点一览
| 方法 | 路径 | 成功 | Scope | 说明 |
|---|---|---|---|---|
| GET | /v1/models | 200 | valid API key | 读取当前可售模型、价格、分辨率、时长与 reference_modes。提交前必须按目录校验能力。 |
| POST | /v1/generations | 201 | generation:create | 创建异步任务;参考图与 referenceMode 在同一个 JSON 请求中提交。 |
| GET | /v1/generations/{id} | 200 | generation:read | 按响应中的 poll_after_ms 查询同一任务,直到终态。 |
| GET | /v1/generations/{id}/content | 200 / 206 | generation:read | 任务成功后下载输出;单区间 Range 请求返回 206。 |
第一步:读取模型能力
不要写死模型能力。只有 reference_modes 列出的模式可以提交;界面也应在提交前隐藏或拦截不兼容组合。最小示例固定演示 seedance-2.5 的 4 秒、480p、无音频请求。
curl --fail-with-body 'https://api.openaiav.com/v1/models' \
--header "Authorization: Bearer $OPENAIAV_API_KEY"最小公网视频示例
完整链路在同一个示例里:创建 → 轮询同一任务 → 下载。 first_frame 使用一张参考图和 adaptive;generateAudio=false 避免请求音频。创建、轮询、下载的成功状态分别是 201、200、200/206;失败响应先读取 HTTP,再读取 error.code。
# Keep both values in environment variables; do not paste secrets into shell history.
# Generate OPENAIAV_IDEMPOTENCY_KEY once for this create intent and keep it unchanged on every retry.
# Set it before the first create, then reuse the exact value after a lost response.
# 1. Create — success: HTTP 201. On failure, the response body contains error.code.
curl --fail-with-body --request POST 'https://api.openaiav.com/v1/generations' \
--header "Authorization: Bearer $OPENAIAV_API_KEY" \
--header "Idempotency-Key: $OPENAIAV_IDEMPOTENCY_KEY" \
--header 'Content-Type: application/json' \
--data '{
"model": "seedance-2.5",
"prompt": "女孩写完一封信,从乡间石屋走入清晨阳光",
"resolution": "480p",
"aspectRatio": "adaptive",
"durationSeconds": 4,
"referenceMode": "first_frame",
"referenceImages": [
"https://developers.openaiav.com/samples/seedance-letter-reference.webp"
],
"generateAudio": false,
"outputFormat": "mp4"
}'
# 2. Save the returned id as TASK_ID. Poll the same id — success: HTTP 200.
curl --fail-with-body 'https://api.openaiav.com/v1/generations/TASK_ID' \
--header "Authorization: Bearer $OPENAIAV_API_KEY"
# Repeat step 2 after poll_after_ms until status is succeeded or failed.
# Never recreate a task whose status is submission_unknown.
# 3. After succeeded, download — success: HTTP 200 (or 206 with Range).
curl --fail-with-body --location 'https://api.openaiav.com/v1/generations/TASK_ID/content' \
--header "Authorization: Bearer $OPENAIAV_API_KEY" \
--output 'result.mp4'请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| model | string | 必填 | 取自 GET /v1/models 的 model;最小视频示例使用 seedance-2.5。 |
| prompt | string | 必填 | 1–4000 字符。全能参考可按数组顺序用 @Image1、@Image2 指代图片。 |
| resolution | string | 可选 | 必须属于所选模型的 resolutions;最小视频示例使用 480p。 |
| aspectRatio | string | 可选 | 必须属于所选模型的 aspect_ratios。图片模型同样生效;当所选模型的首帧能力要求自适应画幅时使用 adaptive。 |
| durationSeconds | integer | 可选 | 视频省略时使用模型最小时长;显式值必须在目录的 duration_seconds 区间内。最小示例使用 4 秒。 |
| referenceMode | first_frame | omni_reference | 使用视频参考图时必填 | 只在目录 reference_modes 明确列出的 Seedance 视频模型上使用。一次请求只能选择一个模式。 |
| referenceImages | string[] | 与 referenceMode 同时填写 | 公网 HTTPS 图片 URL。first_frame 必须且只能 1 张;omni_reference 上限读取 reference_images_max。 |
| inputImages | string[] | 可选 | 仅图片模型的图生图输入,可用 HTTPS 或 data:image/*;上限读取 input_images_max,不得与视频参考模式混用。 |
| generateAudio | boolean | 可选 | 支持音频的视频模型省略时默认 true。最经济示例显式传 false;当前目录没有单列音频附加价,计费始终以 GET /v1/models 为准。 |
| outputFormat | mp4 | mov | 可选 | 只能选择目录 output_formats 中的值;最小示例使用 mp4。 |
参考素材模式
first_frame
first_frame:参考图成为起始画面并决定构图。必须且只能提交 1 张 referenceImages;aspectRatio 取自所选模型的 aspect_ratios,目录含 adaptive 时锁定为 adaptive(输出跟随参考图画幅)。
first_last_frame:提交恰好 2 张 referenceImages,按数组顺序分别是首帧与尾帧,中间画面由模型补全。两张图不要求同尺寸。帧模式与 omni_reference 互斥。
{
"model": "seedance-2.5",
"prompt": "女孩写完一封信,从乡间石屋走入清晨阳光",
"resolution": "480p",
"aspectRatio": "adaptive",
"durationSeconds": 4,
"referenceMode": "first_frame",
"referenceImages": [
"https://developers.openaiav.com/samples/seedance-letter-reference.webp"
],
"generateAudio": false,
"outputFormat": "mp4"
}omni_reference
omni_reference:参考素材用于锁定主体、风格与场景的一致性,不要求成为首帧。除 referenceImages 外,支持的模型还可传 referenceVideos 与 referenceAudios;各类上限见下表,目录未声明的类型提交即 400。提示词按同类型内的数组顺序引用 @Image1、@Video1、@Audio1。
{
"model": "seedance-2.5",
"prompt": "@Image1 保持人物身份与服装一致,女孩从乡间石屋走入清晨阳光",
"resolution": "480p",
"aspectRatio": "16:9",
"durationSeconds": 4,
"referenceMode": "omni_reference",
"referenceImages": [
"https://developers.openaiav.com/samples/seedance-letter-reference.webp"
],
"generateAudio": false,
"outputFormat": "mp4"
}真实兼容范围
接入方式对所有视频模型是同一套:同一个端点、同一组字段,换模型只改 model。差异全部由目录声明——下表就是目录本身,逐个模型列出它支持哪些参考模式、各类素材收几个。目录没声明的能力,提交时会被明确拒绝,不会静默忽略。
首帧细则与尾帧接力
首帧细则:first_frame 与 omni_reference 互斥,同一请求只能选其一;omni 下可用提示词间接引导某张参考图作起始画面,但需要严格首帧一致时,请使用 first_frame 模式提交那张图。Seedance 2.5 的首帧任务画幅固定 adaptive(输出跟随首帧)。尾帧接力:创建时传 returnLastFrame: true,成功后任务额外返回 last_frame_url(与视频同宽高的无水印 PNG,保留 24 小时)——把这个 URL 直接作为下一单 first_frame 的 referenceImages,即可串联多镜头连续叙事,无需任何预注册步骤。
轮询与下载
succeeded 与 failed 才是终态。submission_unknown 是待对账状态:保留原任务 ID,继续轮询,绝不能重放创建请求。成功后优先使用鉴权下载路径 /content,不要依赖任何非 Open AIav 地址。产物保留 24 小时(详情返回 output_expires_at 倒计时;过期后下载返回 410 OUTPUT_EXPIRED,请及时转存)。
| 状态 | 终态 | 处理方式 |
|---|---|---|
| processing | 否 | 已受理;按 poll_after_ms 继续查询。 |
| result_pending | 否 | 输出正在完成结算;继续查询同一任务。 |
| submission_unknown | 否 | 结果待对账;不要重放创建请求,继续保留并查询原任务 ID。 |
| succeeded | 是 | 成功;使用 /content 下载输出。 |
| failed | 是 | 确定失败且预留金额已退回;读取 error_code。 |
旧端点迁移
/v1/assets、/v1/assets/content、/v1/assets/{id}、/v1/asset-groups 与 /v1/asset-groups/{id} 已退役;使用有效密钥及相应旧 scope 时返回 HTTP 410 / ENDPOINT_RETIRED。新接入不得调用这些路径;把 referenceMode 与 referenceImages 放进同一次生成请求。错误码对照
完整对照:HTTP 状态、错误码、含义、建议处置与 SDK 错误类。本表与 SDK 的错误映射同一数据源,未知新码由 SDK 按 HTTP 状态段兜底。
| HTTP | 错误码 | 含义 | 建议处置 | SDK |
|---|---|---|---|---|
| 401 | UNAUTHENTICATED | 缺少或无法识别 API 密钥。 | 带上 Authorization: Bearer oav_… 请求头;密钥只放服务端。 | AuthenticationError |
| 401 | INVALID_API_KEY | 密钥无效或已吊销。 | 在控制台确认密钥状态;必要时轮换生成新密钥。 | AuthenticationError |
| 403 | INSUFFICIENT_SCOPE | 密钥缺少本操作所需 scope。 | 创建任务需 generation:create,查询与下载需 generation:read。 | PermissionError |
| 429 | RATE_LIMITED | 请求超出密钥限频。 | 按 Retry-After / retryAfterSeconds 退避重试;SDK 自动处理。 | RateLimitError |
| 400 | IDEMPOTENCY_KEY_REQUIRED | 创建任务必须携带 Idempotency-Key。 | 为每次新请求生成唯一键;网络重试复用同一键。SDK 自动生成。 | InvalidRequestError |
| 409 | IDEMPOTENCY_KEY_CONFLICT | 同一幂等键配了不同请求体。 | 不同参数请换新键;同参重试保持键与请求体逐字一致。 | InvalidRequestError |
| 400 | MODEL_NOT_FOUND | 未知模型 ID。 | 以 GET /v1/models 返回的 model 为准(如 seedance-2.5-oa)。 | InvalidRequestError |
| 400 | INVALID_PROMPT | 提示词为空或超长。 | 提示词 1–4000 字符。 | InvalidRequestError |
| 400 | INVALID_DURATION | 时长不在模型允许区间。 | 取目录 duration_seconds 区间内整数,或支持时传 -1 智能时长。 | InvalidRequestError |
| 400 | INVALID_RESOLUTION | 分辨率不被该模型支持。 | 取目录 resolutions 中的取值。 | InvalidRequestError |
| 400 | INVALID_ASPECT_RATIO | 画幅不被该模型支持。 | 取目录 aspect_ratios 中的取值;first_frame 场景常锁 adaptive。 | InvalidRequestError |
| 400 | INVALID_REFERENCE_IMAGES | referenceImages 需为公网 HTTPS URL 数组。 | 逐项提供任务期间可读取的 https:// 图片链接。 | InvalidRequestError |
| 400 | INVALID_REFERENCE_IMAGE | 某一项参考图不是合法 URL。 | 错误信息带下标(referenceImages[i]);逐项检查该链接。 | InvalidRequestError |
| 400 | REFERENCE_IMAGE_URL_NOT_HTTPS | 参考图链接不是公网 HTTPS。 | 不支持 http/内网/data URL;请上传到可公网访问的存储。 | InvalidRequestError |
| 400 | REFERENCE_MODE_REQUIRES_IMAGES | 声明了 referenceMode 却没有参考图。 | referenceMode 与 referenceImages 必须同时出现。 | InvalidRequestError |
| 400 | REFERENCE_MODE_NOT_SUPPORTED | 该模型不支持所选参考模式。 | 以目录 reference_modes 为准选择 first_frame / omni_reference。 | InvalidRequestError |
| 400 | FIRST_FRAME_REQUIRES_ONE_IMAGE | first_frame 必须且只能一张参考图。 | 只提交 1 张;多图请改用 omni_reference。 | InvalidRequestError |
| 400 | TOO_MANY_REFERENCES | 参考图数量超过目录上限。 | 上限见目录 reference_images_max。 | InvalidRequestError |
| 400 | INVALID_INPUT_IMAGES | inputImages 需为数组。 | 逐项为 HTTPS URL 或 data:image/* base64。 | InvalidRequestError |
| 400 | INVALID_INPUT_IMAGE | 某一项输入图片格式不合法。 | 逐项需为 HTTPS URL 或 data:image/* base64;错误信息带下标。 | InvalidRequestError |
| 400 | INPUT_IMAGE_TOO_LARGE | 内嵌图片超过 10MB。 | 压缩后重试,或改用公网 HTTPS URL。 | InvalidRequestError |
| 400 | IMAGE_INPUT_NOT_SUPPORTED | 该模型不支持图片输入。 | 仅目录声明 input_images_max>0 的图片模型可用 inputImages。 | InvalidRequestError |
| 400 | TOO_MANY_INPUT_IMAGES | 输入图片数量超上限。 | 上限见目录 input_images_max。 | InvalidRequestError |
| 400 | INSUFFICIENT_BALANCE | 余额不足以预留本次任务。 | 在控制台账单页兑换充值卡后重试。 | InvalidRequestError |
| 400 | LEGACY_ASSET_REFERENCE_RETIRED | 素材 ID 引用已退役。 | 在同一次请求中使用 referenceMode + referenceImages(公网 HTTPS)。 | InvalidRequestError |
| 404 | NOT_FOUND | 任务不存在或不属于当前密钥。 | 确认任务 ID 与密钥归属同一账号。 | InvalidRequestError |
| 409 | OUTPUT_NOT_READY | 产物尚未就绪。 | 继续按 poll_after_ms 轮询任务至终态。 | InvalidRequestError |
| 410 | OUTPUT_EXPIRED | 产物下载窗口(成功后 24 小时)已过。 | 产物请及时转存;过期后需重新生成。detail 的 output_expires_at 可做倒计时。 | OutputExpiredError |
控制台会话面专属码
| HTTP | 错误码 | 含义 | 建议处置 |
|---|---|---|---|
| 400 | REFERENCE_UPLOAD_NOT_FOUND | 本地上传引用不存在、过期或不属于当前账号。 | 在 Playground 重新上传后再运行(上传短时有效)。 |
| 429 | UPLOAD_QUOTA_EXCEEDED | 未使用的上传数量达到上限。 | 先运行任务消费上传,或等待过期后重试。 |
| 429 | WEBHOOK_ENDPOINT_LIMIT | Webhook 端点数量达到上限。 | 删除或停用不再使用的端点。 |
| 400 | INVALID_WEBHOOK_URL | 回调 URL 不是可公网访问的 HTTPS。 | 使用公网 HTTPS 地址;内网/回环地址会被拒绝。 |