跳到正文
文档版本 r15
OpenAPIJSONYAML
API 参考 / Webhook

接收生成通知

generationEvent
事件generationEvent

下面的接口说明为英文原文。

Verify Base64(HMAC-SHA256(signing secret, timestamp + '.' + event_id + '.' + raw_body)) with a constant-time comparison and a five-minute Unix timestamp window. Deduplicate by event_id. Redelivery preserves the body and event_id.

Markdown 文件在 Playground 试运行文档版本 r15

VizoAPI 会把这个请求发送到你在控制台创建的 Webhook 端点。

请求头

请求头
字段说明
X-Relay-Key-IDstring必填
X-Relay-Event-IDstring必填
X-Relay-Timestampstring必填
X-Relay-Signaturestring必填

请求体

JSON 对象,不接受未列出的字段。

请求体
字段说明
billing_statusstring必填

Credits 是冻结、已扣费还是已释放。

closed_statusstring必填
created_atdate-time必填
delivery_statusstring必填

结果是否已保存、可下载。ready 表示可以下载。

error_codestring可选
event_idstring必填
execution_statusstring必填

模型生成进度。

freeboolean必填
late_result_availableboolean必填

关闭后才到的结果,免费提供。

resultobject, 可为 null必填

交付后的素材。

result 的字段
result 的字段
asset_idstring必填
task_idstring必填
typestring必填
generation.succeededgeneration.failedgeneration.canceledgeneration.unresolvedgeneration.refundedgeneration.late_result_available
versioninteger必填

响应

2XX Delivery accepted

请求示例

cURL
# Your endpoint receives a POST. Replay one locally to test your handler:
curl -X POST "$YOUR_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -H "X-Relay-Key-ID: $KEY_ID" \
  -H "X-Relay-Event-ID: $EVENT_ID" \
  -H "X-Relay-Timestamp: $TIMESTAMP" \
  -H "X-Relay-Signature: $SIGNATURE" \
  --data-binary @event.json
Python
import base64, hashlib, hmac, time

def verify(secret: bytes, headers: dict, raw_body: bytes) -> bool:
    ts = headers["X-Relay-Timestamp"]
    if abs(time.time() - int(ts)) > 300:
        return False  # outside the five-minute window
    msg = ts.encode() + b"." + headers["X-Relay-Event-ID"].encode() + b"." + raw_body
    digest = base64.b64encode(hmac.new(secret, msg, hashlib.sha256).digest()).decode()
    return hmac.compare_digest(digest, headers["X-Relay-Signature"])
Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, headers, rawBody) {
  const ts = headers["x-relay-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // outside the five-minute window
  const msg = `${ts}.${headers["x-relay-event-id"]}.${rawBody}`;
  const want = createHmac("sha256", secret).update(msg).digest();
  const got = Buffer.from(headers["x-relay-signature"], "base64");
  return got.length === want.length && timingSafeEqual(got, want);
}
响应事件
{
  "billing_status": "held",
  "closed_status": "string",
  "created_at": "2026-11-02T08:01:43Z",
  "delivery_status": "pending",
  "error_code": "string",
  "event_id": "string",
  "execution_status": "queued",
  "free": false,
  "late_result_available": false,
  "result": null,
  "task_id": "string",
  "type": "generation.succeeded",
  "version": 1
}