指南
进阶用法
Webhook、批量制作、幂等重试、分页和错误处理。
接入正式环境前需要了解的几件事:Webhook、安全重试、错误处理、限流、项目与权限、预算批准、修改版本和删除文件。
完整的接口和字段见 API 参考,这里只讲怎么用。
用 Webhook 接收结果
不想轮询,就登记一个回调地址。视频状态每次变化,Azimo 都会 POST 一个事件过来。登记需要 owner 角色的 Key:
curl -s https://azimo.ai/v1/webhooks \
-H "Authorization: Bearer $AZIMO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: webhook-001" \
-d '{"url": "https://example.com/hooks/azimo", "name": "Production updates"}'
返回里的 signing_secret(以 whsec_ 开头)只显示这一次,请保存好。
事件长这样,type 是 video. 加上状态,例如 video.progress、video.needs_input、video.complete、video.rejected、video.failed、video.cancelled:
{"id": "d8009f54780243ea", "sequence": 12, "type": "video.complete", "api_version": "v1", "project_id": "c56eb945e4464aec", "created_at": 1790000000, "data": {"id": "b6bf4689035d474f", "status": "complete", "stage": "complete", "progress": 100}}
每个请求带两个头:Vidgen-Event-Id(事件 ID)和 Vidgen-Signature: t=<时间戳>,v1=<签名>。签名是 HMAC-SHA256(signing_secret, "<时间戳>." + 原始请求体) 的十六进制。一定要对收到的原始字节验签,不要先解析 JSON 再序列化:
import hashlib, hmac, time
def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
try:
parts = dict(item.split("=", 1) for item in header.split(","))
timestamp = int(parts["t"])
except (KeyError, ValueError):
return False
if abs(time.time() - timestamp) > tolerance: # 拒绝 5 分钟以前的请求
return False
expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
Python SDK 自带同样的函数 Vidgen.verify_webhook(secret, header, body),TypeScript SDK 是 Vidgen.verifyWebhook(secret, header, body)。
收到事件后:
- 验签通过就尽快返回 2xx,耗时的处理放到自己的队列里。
- 投递失败会自动重试,最长持续约 72 小时,所以同一个事件可能到达多次:请按事件
id去重。 - 事件不保证按顺序到达。拿不准时,用
GET /v1/videos/{id}查最新状态。 - 以后可能增加新的事件类型,遇到不认识的
type直接忽略即可。 - 下载链接会过期;需要时重新查询视频,拿新链接。
也可以只给某一条视频设回调:在 POST /v1/videos 里加 webhook_url,响应里的 webhook_signing_secret 就是验签用的密钥。不用 Webhook 的话,可以用 GET /v1/events?after=<sequence> 按顺序拉取事件。
安全重试:Idempotency-Key
所有创建类的 POST(上传、方案、制作、修改、取消、回答、Webhook 等)都接受请求头 Idempotency-Key,长度 1–128 个字符。
- 同一个 Key、同样的请求体:返回第一次的结果,不会再做一次。
- 同一个 Key、不同的请求体:返回
409,错误码idempotency_conflict。 - 换一个新 Key:就是一个新请求。对同一个方案换 Key 再提交,会再做一条视频。
做法:在发请求前生成 Key,和你的业务记录一起保存;超时或断线后,用同一个 Key 重试。
处理错误
所有错误都是同一种格式:
{"error": {"code": "validation_error", "message": "request validation failed", "details": [{"loc": ["body", "options", "duration_max"], "msg": "Input should be less than or equal to 180", "type": "less_than_equal"}], "request_id": "64ceb19e540b438f8b9a4df3bfe62ba7"}}
按 code 判断,不要按 message 的文字判断。每个响应都有 X-Request-ID 头;联系我们时请附上 request_id。
| HTTP | code | 怎么办 |
|---|---|---|
| 401 | unauthenticated | Key 缺失、错误或已撤销,换一把有效的 Key |
| 402 | insufficient_balance / budget_exceeded | 余额不足或达到额度上限;充值或联系 sales@azimo.ai,不要反复重试 |
| 403 | forbidden | 角色或项目不允许,例如 read-only key |
| 403 | contact_sales | 与价格相关的请求,请联系 sales@azimo.ai |
| 404 | not_found | ID 不存在,或不在当前项目里 |
| 409 | conflict / idempotency_conflict | 状态不允许(例如视频已结束),或 Key 被用于不同的请求 |
| 413 | payload_too_large / storage_quota_exceeded | 文件超过 60 MB,或存储空间已满,删掉不用的素材 |
| 415 | unsupported_media_type | 不支持的文件类型 |
| 422 | validation_error | 请求字段不对,details 列出具体问题 |
| 429 | rate_limited | 请求太频繁,按 Retry-After 等待后重试 |
| 500 | internal_error | 我们这边出错,带上 request_id 联系我们 |
| 503 | backend_unconfigured | 这个工作流暂时不可用 |
限流与 429
- 每把 Key 默认每分钟最多 600 次 API 请求。
- 每个组织每小时能开始的制作数量有上限;Key 也可以单独设更低的上限。
- 超出时返回
429,响应头Retry-After是需要等待的秒数。
Python SDK 会对 GET 和带 Idempotency-Key 的 POST 自动重试 429 和 5xx,并遵守 Retry-After。轮询视频状态时,每 10 秒左右一次就够了。
项目与 Key 的角色
资源(素材、方案、视频、Webhook)都属于某个项目。请求头 X-Project-ID 选择项目,不传就用默认项目。组织 owner 可以用 POST /v1/projects 新建项目,用 POST /v1/api-keys 创建 Key 并指定 role 和 project_id。
| 角色 | 能做什么 |
|---|---|
viewer | 只读:查看视频、方案、素材、事件和余额 |
editor | 另外可以上传、创建方案、开始制作、取消、回答和修改 |
owner(绑定项目) | 另外可以管理本项目的 Webhook |
owner(不绑定项目) | 组织 owner:管理所有项目和 Key |
每个应用或客户端单独用一把 Key,按最小权限选择角色。
预算批准
制作过程中如果要超出这条视频的花费上限,视频会暂停在 needs_input,result.input_required 是:
{"code": "budget_approval", "actor": "customer", "message": "…", "approvable": true}
同意继续,就回答:
curl -s https://azimo.ai/v1/videos/b6bf4689035d474f/resume \
-H "Authorization: Bearer $AZIMO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: approve-b6bf-001" \
-d '{"approve_budget": true}'
SDK 是 azimo.approve_budget(video_id),命令行是 azimo resume ID --approve-budget。批准后仍然需要余额足够,否则返回 402;已经完成的步骤不会重做。
其他 needs_input 用文字回答:{"message": "..."},需要补资料时加上 "assets": ["<素材 ID>"]。长时间不回应(默认 7 天)的视频会自动取消。
修改版本
对已结束的视频(complete、rejected、failed、cancelled 或 needs_input)可以做一个修改版:
curl -s https://azimo.ai/v1/videos/b6bf4689035d474f/revisions \
-H "Authorization: Bearer $AZIMO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: revise-b6bf-001" \
-d '{"prompt": "完整的新 brief:同样的产品,结尾强调一次能烧两杯水。", "options": {"subtitles": true}}'
- 返回一条新视频,
parent_id指向原视频,原视频保留不变。 prompt会整体替换原来的 brief,请写完整;options只改你传的字段;assets不传就沿用原来的素材(原素材已删除时会返回404,这时请重新上传并传assets)。- 修改版是一次完整的新制作,会使用余额。视频还在制作中时返回
409。
取消与删除文件
- 取消:
POST /v1/videos/{id}/cancel。排队或等待中的视频立即取消;正在制作的会在下一步开始前停下。取消的视频按已经花掉的用量收费。 - 质检不过不收费:以
rejected(未通过质检)或failed(系统未能完成)结束的视频不扣余额,冻结额度全部退回,钱包流水里有一条金额为 0 的settle记录说明原因。 - 删除素材:
DELETE /v1/assets/{id}。已经用它做好的视频不受影响,但之后基于这条视频做修改版时要重新提供素材。 - 删除视频文件:
DELETE /v1/videos/{id},只能删已结束的视频(先取消)。成片、字幕和封面会被清除,下载链接失效,视频记录保留。 - 品牌、模板和 Webhook 也可以用
DELETE删除。 - 成片只保留一段时间,请及时下载保存。