SeeAPI 客户接入文档
本文档面向第一批 API 客户,覆盖视频任务提交、任务查询、模型列表、余额查询、计费行为、错误码和 Webhook 验签。示例基础地址为预生产地址;正式域名备案完成后,请替换为平台提供的正式基础地址。
https://api.43.160.233.194.sslip.ioAuthorization: Bearer sk_live_...Idempotency-Key: client-generated-key认证与安全
外部 API 使用 API Key 认证。创建 API Key 时,完整密钥只展示一次;之后控制台只展示 key_prefix, 请在服务端安全保存密钥,不要放进前端代码、日志、截图或工单。
- 所有公开 API 请求都带
Authorization: Bearer sk_live_...。 - API Key 无效返回
401 invalid_api_key;被暂停或禁用返回 403 系列错误。 - 建议每次提交任务都带业务侧唯一
Idempotency-Key,例如订单号或请求流水号。
幂等、计费与恢复规则
- 同一用户使用同一个
Idempotency-Key和相同请求体,会返回同一个任务,不会重复扣费。 - 同一个
Idempotency-Key搭配不同请求体,会返回409 idempotency_conflict。 - 平台在创建任务前预扣预计费用;任务成功后按已预扣金额正式结算。
- 任务失败或取消后,Worker 会自动退款,任务最终通常表现为 refunded。
- 余额不足返回
402 insufficient_credits,不会创建任务,并会把当前账户下 active API Key 暂停为balance_paused。 - 充值后只恢复
balance_paused的 API Key,不恢复user_disabled、admin_disabled或risk_blocked。
/v1/video/generations提交视频任务
创建异步视频生成任务。成功时返回 202 Accepted 和任务 ID。
curl https://api.43.160.233.194.sslip.io/v1/video/generations \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-20260510-0001" \
-d '{
"model": "seedance-2.0-face-video",
"prompt": "生成一段自然柔光下的电影感真人肖像视频。",
"face_reference_url": "https://example.com/assets/face.jpg",
"image_reference_url": "https://example.com/assets/reference.jpg",
"duration": 5,
"aspect_ratio": "9:16",
"callback_url": "https://client.example.com/webhooks/seeapi"
}'请求体字段
| 字段 | 要求 | 说明 |
|---|---|---|
model | 必填 | 当前公开模型为 seedance-2.0-face-video。后续多模型会复用同一接口。 |
prompt | 必填 | 视频提示词,1 到 4000 字符。 |
face_reference_url | 必填 | 真人脸参考资源 URI。当前模型要求提供该字段。 |
image_reference_url | 可选 | 画面参考图 URI,用于补充构图或风格。 |
duration | 必填 | 整数,当前支持 5 或 10 秒。 |
aspect_ratio | 必填 | 当前支持 9:16、16:9、1:1。 |
callback_url | 可选 | 接收任务 Webhook 通知的地址。当前 MVP 稳定投递成功事件;生产环境请使用 HTTPS。 |
/v1/tasks/{task_id}查询任务
轮询任务状态,直到进入 succeeded、refunded、failed 或 canceled。
curl https://api.43.160.233.194.sslip.io/v1/tasks/job_xxx \
-H "Authorization: Bearer sk_live_xxx"
# 成功响应示例
{
"id": "job_xxx",
"object": "task",
"status": "succeeded",
"model": "seedance-2.0-face-video",
"output": {
"video_url": "https://cdn.example.com/users/usr_xxx/jobs/job_xxx/output/video.mp4",
"assets": [
{
"type": "output_video",
"url": "https://cdn.example.com/users/usr_xxx/jobs/job_xxx/output/video.mp4",
"mime_type": "video/mp4",
"size_bytes": "12345678",
"checksum": "sha256:..."
}
]
},
"error": null,
"cost": {
"estimated_units": 5000000,
"charged_units": 5000000,
"refunded_units": 0,
"currency": "credits"
},
"created_at": "2026-05-10T08:00:00.000Z",
"finished_at": "2026-05-10T08:01:00.000Z"
}任务状态
| 状态 | 含义 |
|---|---|
created | 任务已持久化,等待入队;提交响应中会按 queued 展示。 |
queued | 已进入队列,等待 Worker 处理。 |
running | 已开始提交或轮询上游模型。 |
succeeded | 任务成功,余额正式结算,output 中返回平台存储后的结果地址。 |
failed | 任务失败的中间状态;Worker 会继续执行退款流程。 |
refunded | 任务失败或取消后已退款,cost.refunded_units 展示退款数量。 |
canceled | 任务已取消;如果已预扣,后续会进入退款流程。 |
/v1/models模型列表
返回当前 API Key 可调用的公开或 beta 模型。当前只公开 seedance-2.0-face-video;后续多模型会复用同一接口。
curl https://api.43.160.233.194.sslip.io/v1/models \
-H "Authorization: Bearer sk_live_xxx"
# 响应示例
{
"data": [
{
"code": "seedance-2.0-face-video",
"modality": "video",
"provider": "seedance",
"execution_mode": "async",
"status": "public",
"input_schema": {
"required": ["model", "prompt", "face_reference_url", "duration", "aspect_ratio"]
},
"pricing_rule": {
"type": "fixed_by_duration",
"currency": "credits"
}
}
]
}/v1/credits查询余额
返回账户余额、币种和因余额不足暂停的 API Key 数量。
curl https://api.43.160.233.194.sslip.io/v1/credits \
-H "Authorization: Bearer sk_live_xxx"
# 响应示例
{
"balance_units": 12000000,
"currency": "credits",
"paused_api_keys": 0
}Webhook 事件与签名
提交任务时传入 callback_url 后,可用 Webhook 接收任务通知。当前 MVP 稳定投递 task.succeeded;核心事件格式已覆盖 task.refunded、task.failed和 task.canceled,这些非成功终态会在后续版本升级为稳定投递承诺。请始终以 /v1/tasks/{task_id} 作为最终状态兜底;Webhook 投递失败不会改变任务最终状态, 也不会再次触发扣费或退款。
- Header:
x-webhook-id、x-webhook-timestamp、x-webhook-signature。 - 签名算法:
HMAC_SHA256(secret, "{timestamp}.{rawBody}"),Header 值格式为v1=hex_hmac_sha256。 - 验签时必须使用收到的原始请求体 raw body,不要使用重新序列化后的 JSON。
client callback_urlWebhook Payload
succeeded 事件会包含 output;refunded、failed、canceled 的事件格式中 output 为 null,并包含 error。当前 MVP 请不要依赖非成功终态一定投递。
{
"id": "evt_xxx",
"type": "task.succeeded",
"created_at": "2026-05-10T08:01:00.000Z",
"data": {
"id": "job_xxx",
"status": "succeeded",
"model": "seedance-2.0-face-video",
"output": {
"video_url": "https://cdn.example.com/users/usr_xxx/jobs/job_xxx/output/video.mp4"
},
"error": null
}
}x-webhook-signatureNode.js Webhook 验签
示例使用 Node.js 内置 http 和 crypto。请将 SEEAPI_WEBHOOK_SECRET 配置为平台为你的回调地址分配的密钥。
import { createHmac, timingSafeEqual } from "node:crypto";
import http from "node:http";
const WEBHOOK_SECRET = process.env.SEEAPI_WEBHOOK_SECRET;
function verifySignature(rawBody, timestamp, signature) {
if (!WEBHOOK_SECRET || !timestamp || !signature?.startsWith("v1=")) return false;
const expected = "v1=" + createHmac("sha256", WEBHOOK_SECRET)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const receivedBuffer = Buffer.from(signature);
const expectedBuffer = Buffer.from(expected);
return receivedBuffer.length === expectedBuffer.length
&& timingSafeEqual(receivedBuffer, expectedBuffer);
}
http.createServer((req, res) => {
if (req.method !== "POST") {
res.writeHead(405).end();
return;
}
const chunks = [];
req.on("data", (chunk) => chunks.push(chunk));
req.on("end", () => {
const rawBody = Buffer.concat(chunks).toString("utf8");
const timestamp = req.headers["x-webhook-timestamp"];
const signature = req.headers["x-webhook-signature"];
if (!verifySignature(rawBody, String(timestamp ?? ""), String(signature ?? ""))) {
res.writeHead(401).end("invalid signature");
return;
}
const event = JSON.parse(rawBody);
console.log(req.headers["x-webhook-id"], event.type, event.data.id);
res.writeHead(204).end();
});
}).listen(3000);统一错误格式
所有平台错误都使用统一结构;message 可用于排查,业务判断请优先依赖稳定的 code。
{
"error": {
"code": "insufficient_credits",
"message": "Insufficient credits.",
"type": "billing_error",
"request_id": "req_xxx"
}
}| 错误码 | 类型 | HTTP | 说明 |
|---|---|---|---|
invalid_request | invalid_request_error | 400 | 请求结构不合法时的通用说明;当前代码更常返回 validation_error、invalid_json 或 missing_required_field。 |
validation_error | invalid_request_error | 400 | 请求体字段缺失、类型错误或不符合模型 input_schema。 |
unauthorized | authentication_error | 401 | 未登录或认证失败;API Key 无效时通常返回 invalid_api_key。 |
insufficient_credits | billing_error | 402 | 余额不足,平台不会创建任务,并会暂停当前账户下 active API Key。 |
idempotency_conflict | invalid_request_error | 409 | 同一 Idempotency-Key 已用于不同请求体。 |
model_not_found | model_error | 404 | 模型不存在。 |
model_disabled | model_error | 403 | 模型已禁用。 |
provider_not_configured | model_error | 500 | 模型对应的 Provider 未配置。 |
provider_invalid_request | provider_error | 422 | 上游认为请求无效。 |
provider_unavailable | provider_error | 502 | 上游暂不可用。 |
provider_rate_limited | provider_error | 429 | 上游限流。 |
provider_timeout | provider_error | 503 | 上游超时。 |
internal_error | internal_error | 500 | 平台内部错误。 |
/v1/video/generationsNode.js 提交并轮询
适用于 Node.js 18+,API Key 从服务端环境变量读取。
const BASE_URL = "https://api.43.160.233.194.sslip.io";
const API_KEY = process.env.SEEAPI_API_KEY;
async function main() {
const submit = await fetch(`${BASE_URL}/v1/video/generations`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order-20260510-0001"
},
body: JSON.stringify({
"model": "seedance-2.0-face-video",
"prompt": "生成一段自然柔光下的电影感真人肖像视频。",
"face_reference_url": "https://example.com/assets/face.jpg",
"image_reference_url": "https://example.com/assets/reference.jpg",
"duration": 5,
"aspect_ratio": "9:16",
"callback_url": "https://client.example.com/webhooks/seeapi"
})
});
const task = await submit.json();
if (!submit.ok) throw new Error(JSON.stringify(task));
while (true) {
const res = await fetch(`${BASE_URL}/v1/tasks/${task.id}`, {
headers: { Authorization: `Bearer ${API_KEY}` }
});
const current = await res.json();
if (!res.ok) throw new Error(JSON.stringify(current));
if (["succeeded", "refunded", "failed", "canceled"].includes(current.status)) {
console.log(current);
return;
}
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});/v1/video/generationsPython 提交并轮询
示例使用 requests;API Key 从服务端环境变量 SEEAPI_API_KEY 读取。
import os
import time
import requests
BASE_URL = "https://api.43.160.233.194.sslip.io"
API_KEY = os.environ["SEEAPI_API_KEY"]
payload = {
"model": "seedance-2.0-face-video",
"prompt": "生成一段自然柔光下的电影感真人肖像视频。",
"face_reference_url": "https://example.com/assets/face.jpg",
"image_reference_url": "https://example.com/assets/reference.jpg",
"duration": 5,
"aspect_ratio": "9:16",
"callback_url": "https://client.example.com/webhooks/seeapi"
}
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "order-20260510-0001",
}
submit = requests.post(f"{BASE_URL}/v1/video/generations", json=payload, headers=headers, timeout=30)
submit.raise_for_status()
task = submit.json()
while True:
res = requests.get(
f"{BASE_URL}/v1/tasks/{task['id']}",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
)
res.raise_for_status()
current = res.json()
if current["status"] in ["succeeded", "refunded", "failed", "canceled"]:
print(current)
break
time.sleep(3)