FAL 格式 Webhook
FAL 格式接口创建的是异步任务。除了轮询任务状态,你还可以在提交任务时提供 Webhook 地址,由 Modelink 在任务状态变化时向该地址发送 POST 请求。
Webhook 适合生成图片、视频等耗时较长的任务。接收端返回 2xx 时,Modelink 会将本次投递判定为成功;请求超时或返回非 2xx 状态码时会按重试策略再次投递。
信息
本页说明 Modelink 的 FAL 兼容 Webhook。载荷主体与 FAL 格式兼容;Modelink
还会发送 IN_PROGRESS 进度回调,这是相对 FAL 官方终态回调的扩展。
配置回调地址
FAL 格式接口统一通过 Query 参数 fal_webhook 配置回调地址,这是当前推荐的调用方式。
调用 FAL 格式接口时,鉴权请求头使用 Authorization: Key <api_key>,与 FAL 官方格式保持一致。
回调地址必须满足以下要求:
- 使用
https://。 - 能从公网访问,不能指向本机、内网或其他受限地址。
- 不要依赖 Cookie、浏览器登录态或 Modelink API Key。
- 不要使用会跳转到其他地址的 URL;Webhook 投递不会跟随重定向。
下面以视频生成接口为例,通过 fal_webhook 指定回调地址。Query 参数中的 URL 必须进行 URL 编码:
export MODELINK_API_KEY="替换为你的 Modelink API Key"
export MODELINK_BASE_URL="https://api.qnaigc.com"
curl --request POST \
--url "$MODELINK_BASE_URL/queue/bytedance/seedance-2.0/text-to-video?fal_webhook=https%3A%2F%2Fexample.com%2Fwebhooks%2Fmodelink" \
--header "Authorization: Key $MODELINK_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"prompt": "A paper boat drifting through a rainy neon city"
}'任务提交成功后,接口仍会立即返回 IN_QUEUE 和 request_id。请保存 request_id,它既用于查询任务,也用于关联后续 Webhook。
回调请求
Modelink 使用 Content-Type: application/json 向你的地址发送 POST 请求。通用结构如下:
| 字段 | 类型 | 说明 |
|---|---|---|
request_id | string | 任务 ID;与创建任务时返回的 request_id 一致 |
gateway_request_id | string | FAL 兼容字段;当前与 request_id 相同 |
status | string | IN_PROGRESS、OK 或 ERROR |
payload | object | null | 任务结果、错误详情;IN_PROGRESS 时为 null |
error | string | 失败原因,仅 ERROR 回调中可能出现 |
payload_error | string | FAL 兼容的可选字段;结果无法序列化为 JSON 时可能出现,不应作为固定字段依赖 |
Webhook 的 status 与查询接口的队列状态不是同一组枚举:
| Webhook 状态 | 含义 | payload |
|---|---|---|
IN_PROGRESS | 任务正在处理 | null |
OK | 任务成功完成 | 模型结果,例如 images 或 video |
ERROR | 任务失败或未能完成 | 错误详情,通常包含 detail;同时可能提供 error |
处理中
同一个任务可能在进入处理、下载或上传等阶段时收到 IN_PROGRESS 回调:
{
"request_id": "qvideo-user-1770000000000000000",
"gateway_request_id": "qvideo-user-1770000000000000000",
"status": "IN_PROGRESS",
"payload": null
}成功结果
图片任务成功时,payload 通常包含 images:
{
"request_id": "qimage-user-1770000000000000000",
"gateway_request_id": "qimage-user-1770000000000000000",
"status": "OK",
"payload": {
"images": [
{
"url": "https://example-cdn.com/result/image.png",
"content_type": "image/png",
"file_name": "image.png",
"file_size": 1824075,
"width": 1024,
"height": 1024
}
]
}
}视频任务成功时,payload 通常包含 video:
{
"request_id": "qvideo-user-1770000000000000000",
"gateway_request_id": "qvideo-user-1770000000000000000",
"status": "OK",
"payload": {
"video": {
"url": "https://example-cdn.com/result/video.mp4",
"content_type": "video/mp4",
"file_name": "video.mp4",
"file_size": 8482016,
"duration": 5
}
}
}不同模型的结果字段可能不同。解析 payload 时应以对应接口的结果响应结构为准,并允许增加新字段。结果 URL 通常有有效期,收到成功回调后应尽快转存到自己的受控存储。
失败结果
任务失败时,status 为 ERROR,error 提供简要原因,payload.detail 提供结构化错误详情:
{
"request_id": "qvideo-user-1770000000000000000",
"gateway_request_id": "qvideo-user-1770000000000000000",
"status": "ERROR",
"error": "prompt is required",
"payload": {
"detail": [
{
"loc": ["body", "prompt"],
"msg": "field required",
"type": "value_error.missing",
"url": ""
}
]
}
}detail 需要按宽松结构处理:不同错误来源可能返回数组、对象或字符串。
接收与幂等处理
Webhook 采用至少一次投递语义:网络错误、超时或非 2xx 响应都可能触发重复投递。建议接收端遵循以下流程:
- 读取并校验 JSON,记录
request_id、status和接收时间。 - 使用
request_id + status作为幂等键,重复回调直接返回2xx。 - 将耗时的下载、转存和业务处理放入自己的任务队列。
- 返回
2xx确认接收;下载、转存等耗时业务由接收端自行调度。 - 只允许任务状态向前推进;如果终态后又收到较早的
IN_PROGRESS,应忽略该状态回退。
以下是一个精简的 Node.js 接收示例:
import { createServer } from "node:http";
const received = new Set(); // 生产环境请使用数据库或持久化缓存
createServer((request, response) => {
if (request.method !== "POST") {
response.writeHead(405).end();
return;
}
let rawBody = "";
request.on("data", (chunk) => {
rawBody += chunk;
});
request.on("end", () => {
try {
const event = JSON.parse(rawBody);
const key = `${event.request_id}:${event.status}`;
if (!received.has(key)) {
received.add(key);
// 把 event 写入队列,在后台处理 payload。
}
response.writeHead(204).end();
} catch {
response.writeHead(400).end();
}
});
}).listen(3000);超时与重试
Modelink 的当前投递策略如下:
- 单次请求超时为 30 秒。
2xx表示接收成功;网络错误、超时、重定向和其他 HTTP 状态码均视为失败。- 首次失败后最多重试 3 次,间隔约为 2 秒、4 秒和 8 秒,即最多投递 4 次。
Webhook 不能替代任务查询接口。若业务要求可靠收敛,建议保存创建任务时返回的 request_id,并对长时间未收到终态回调的任务进行低频补偿查询。
安全建议
- 在回调 URL 路径中加入不可预测的随机令牌,例如
/webhooks/modelink/<random-token>,并定期轮换。 - 对请求体设置大小上限,只接受
POST和application/json。 - 不要仅凭媒体 URL 的域名判断回调可信,也不要在日志中完整记录带临时凭证的结果 URL。
- 当前 Modelink 回调不提供 FAL 官方的
X-Fal-Webhook-*签名请求头,不要直接套用 FAL 官方签名校验流程。 - 需要更严格鉴权时,可在自己的接收层使用独立域名、随机路径、来源网络策略和后续任务查询进行交叉校验。