开发者 API
使用 API key 鉴权、创建生成任务、追踪积分消耗,并正确处理错误与退款。
概述
VisioArt 对外提供一套开发者 REST API,直接接入与产品控制台相同的生成流水线。API 请求会使用调用账户自己的余额,扣减同一套 credits,并把生成记录与 usage 事件写入同一套后台数据。
适合的场景包括:
- 发现当前工作区内已激活的模型目录、可用模式与价格证据
- 从你自己的应用中发起生成任务
- 不依赖控制台页面,直接轮询任务状态
- 通过稳定的 API 路由下载生成资产
- 在你自己的后端中对账扣费与退款流水
基础地址
将你部署后的 VisioArt 域名作为 API 基础地址:
https://your-domain.com/api/v1鉴权方式
在 Settings -> API Keys 中创建 API key。每把 key 都继承所属账户的余额与权限范围。
只有付费方案用户才能创建 API key。
你可以使用以下任一请求头:
Authorization: Bearer visioart_your_api_key或:
x-api-key: visioart_your_api_key除非两者值完全相同,否则不要在同一个请求里同时发送两种凭证。
积分模型
- API 生成任务与网页登录后的产品共用同一钱包余额。
- 生成任务成功入队时即会扣费。
- 若任务最终失败或被取消,系统会在任务进入可退款终态时自动退回 credits。
- 如果账户余额低于本次任务预估消耗,创建接口会直接返回
402 insufficient_credits。
幂等语义
POST /api/v1/generations 必须携带 Idempotency-Key 请求头。
规则如下:
- 同一个 key 配合同一份请求体重放,会返回第一次请求的结果。
- 同一个 key 如果配不同请求体重用,会返回
409 idempotency_conflict。 - 该请求头最多 200 个字符,只允许
A-Z a-z 0-9 . _ : -。
示例:
Idempotency-Key: 6d1d0f58-d65b-474a-8d1d-7a91fd8bd8dc响应结构
成功的 JSON 响应都带有 request_id:
{
"request_id": "38285b04-43a5-440f-8bb8-5e8c32e86920",
"data": {}
}错误响应使用统一 envelope:
{
"request_id": "1f1f8258-ae62-4c65-8e06-f9633dc518df",
"error": {
"code": "insufficient_credits",
"message": "Insufficient credits"
}
}同一个值也会通过 x-request-id 响应头返回。
接口列表
查询模型与能力目录
curl -X GET "https://your-domain.com/api/v1/models" \
-H "Authorization: Bearer visioart_your_api_key"响应:
{
"request_id": "2b4fa4fa-3419-4d92-95ad-d4d08a838bea",
"data": {
"object": "list",
"total": 26,
"items": [
{
"object": "model",
"model_id": "qwen2",
"display_name": "Qwen2",
"availability": "active",
"modes": [
{
"generator_mode": "text-to-image",
"supported_aspect_ratios": ["16:9", "9:16", "1:1"],
"supported_duration_seconds": [5],
"supported_output_formats": ["png", "jpg"],
"public_model_options": [],
"pricing": {
"variants": [
{
"id": "default",
"request_model_options": null,
"credit_matrix": [
{
"aspect_ratio": "16:9",
"duration_seconds": 5,
"credits": 6,
"source_type": "legacy_exact_matrix",
"source_updated_at": "2026-04-22T11:09:35.262Z"
}
]
}
]
}
}
]
}
]
}
}模型目录说明:
- 该接口只返回当前工作区内已激活、且能够被明确枚举能力边界的模型;未启用或配置不完整的模型不会被猜测性暴露。
modes[*].public_model_options只列出当前公开POST /generations请求体允许提交、且业务校验链实际接受的 option 家族。pricing.variants[*].request_model_options故意保持与POST /generations的modelOptions请求结构一致,便于直接复用。credit_matrix[*].source_type会标明每个 credit 值来自workspace_override、market_catalog、legacy_exact_matrix还是built_in_estimate。- 当价格来自已审核的市场定价目录或生成后的精确 credit matrix 时,
credit_matrix[*].source_updated_at会返回对应审核日期或矩阵生成时间;其余来源可能为null。
查询余额
curl -X GET "https://your-domain.com/api/v1/credits/balance" \
-H "Authorization: Bearer visioart_your_api_key"响应:
{
"request_id": "38285b04-43a5-440f-8bb8-5e8c32e86920",
"data": {
"balance": 1000,
"unit": "credits"
}
}创建生成任务
curl -X POST "https://your-domain.com/api/v1/generations" \
-H "Authorization: Bearer visioart_your_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6d1d0f58-d65b-474a-8d1d-7a91fd8bd8dc" \
-d '{
"title": "veo31-fast text-to-video",
"modelId": "veo31-fast",
"generatorMode": "text-to-video",
"prompt": "A clean product reveal with cinematic camera movement",
"aspectRatio": "16:9",
"durationSeconds": 8,
"uploads": []
}'响应:
{
"request_id": "d587724c-df59-4333-9d4a-2ce8d2988466",
"idempotent_replay": false,
"data": {
"id": "9a87675c-1e1a-4b16-873c-19ffd8e79cdc",
"object": "generation",
"status": "processing",
"title": "veo31-fast text-to-video",
"model_id": "veo31-fast",
"generator_mode": "text-to-video",
"prompt": "A clean product reveal with cinematic camera movement",
"aspect_ratio": "16:9",
"duration_seconds": 8,
"output_format": null,
"estimated_credits": 30,
"error_message": null,
"result_url": null,
"outputs": [],
"queued_at": "2026-04-05T13:27:59.824Z",
"completed_at": null,
"created_at": "2026-04-05T13:27:59.824Z",
"updated_at": "2026-04-05T13:28:01.903Z"
}
}请求体规则:
- 对外创建任务 schema 是严格模式。未知字段或内部字段会直接返回
400 invalid_request。 uploads只接受{ "kind": "...", "url": "https://..." }这种对象结构。- 每个 upload 的
url都必须已经指向受信任的远程资产地址,来源只能是工作区存储或受信任的 provider 托管地址。 modelOptions如果传入,只能使用当前modelId对应的公开 option 家族;无关 option 或未知嵌套字段都会被拒绝。imageCount只有在对应/models条目的public_model_options[].path暴露为"modelOptions.imageCount"时才允许传入;提交前可通过 pricing variants 看到对应扣费。- 不要传
modelOptions: {}或modelOptions: { "kling30": {} }这种空的 no-op 对象。 - 不要发送
landingRecordId、landingKind、landingPathname、estimatedCredits、storagePath、fileName、required这类内部字段。
生成任务响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id | string(UUID) | VisioArt 生成任务的 ID。 |
object | "generation" | 常量字面量。 |
status | "queued" | "processing" | "completed" | "failed" | "cancelled" | 终态:completed、failed、cancelled。 |
title | string | 未传时默认 "{modelId} {generatorMode}"。 |
model_id | string | 本次请求选用的模型。 |
generator_mode | string | text-to-video、image-to-video、video-to-video、effect、image-editor、text-to-image 或 video-compression。 |
prompt | string | 对于不强制 prompt 的模式可为空串。 |
aspect_ratio | string | 16:9、9:16、1:1、4:3、3:4、3:2、2:3 之一。 |
duration_seconds | number | 3-15 之间的整数。 |
output_format | "png" | "jpg" | "webp" | null | 仅在支持输出格式的图像模式下返回。 |
estimated_credits | number | 入队时扣减的 credits;任务 failed 或安全 cancelled 时退还。 |
error_message | string | null | 仅在 failed 时非空。 |
result_url | string | null | 等价于 outputs[0].url,outputs 为空时为 null。 |
outputs | GenerationOutput[] | 见下表;任务未产出资产前为空数组。 |
queued_at | string(ISO-8601) | 任务入队时间。 |
completed_at | string | null(ISO-8601) | 到达终态时写入。 |
created_at | string(ISO-8601) | 行创建时间。 |
updated_at | string(ISO-8601) | 最近一次状态迁移时间。 |
生成产出对象(outputs[i]):
| 字段 | 类型 | 说明 |
|---|---|---|
id | string(UUID) | 资产 ID,可用于 /assets/{assetId}。 |
kind | string | 通常为 video 或 image,与 generator mode 对应。 |
url | string | VisioArt 的资产路由(/api/v1/assets/{id}),不是 provider 的原始地址。 |
mime_type | string | null | 在 provider 返回 mime type 后填充。 |
width | number | null | 像素;元数据未知前为 null。 |
height | number | null | 像素;元数据未知前为 null。 |
duration_seconds | number | null | 图片产出固定为 null。 |
created_at | string(ISO-8601) | 资产行创建时间。 |
查询任务
curl -X GET "https://your-domain.com/api/v1/generations/9a87675c-1e1a-4b16-873c-19ffd8e79cdc" \
-H "Authorization: Bearer visioart_your_api_key"取消任务
curl -X POST "https://your-domain.com/api/v1/generations/9a87675c-1e1a-4b16-873c-19ffd8e79cdc/cancel" \
-H "Authorization: Bearer visioart_your_api_key"取消只适用于仍停留在 VisioArt 本地队列、且尚未开始上游提交流程的任务。
实际判断上,这意味着任务必须仍处于 queued,还没有拿到 provider task ID,并且还没有被 worker 领取进入提交流程。
取消成功后,任务会切换为 cancelled,此前已扣除的 credits 会写入对应退款记录。
一旦任务已经开始上游提交流程,接口就会返回 409 generation_not_cancellable。这样可以避免在上游 provider 并不支持真实取消时,对外错误承诺“已经取消”。
查询 usage 事件
curl -X GET "https://your-domain.com/api/v1/usage?limit=20&offset=0" \
-H "Authorization: Bearer visioart_your_api_key"查询参数:
| 名称 | 类型 | 默认 | 范围 | 说明 |
|---|---|---|---|---|
limit | number | 20 | 1-100 | 单页数量。 |
offset | number | 0 | 0-10000 | 零基偏移。 |
apiKeyId | string | — | 1-255 字符 | 可选,按指定 API key 过滤事件。 |
响应结构:
{
"request_id": "…",
"data": {
"items": [
{
"id": "…",
"api_request_id": "…",
"api_key_id": "…",
"generation_job_id": "…",
"credit_transaction_id": "…",
"event_type": "charge",
"credits_delta": -20,
"balance_before": 1000,
"balance_after": 980,
"pricing_snapshot": "{\"schemaVersion\":1,\"modelId\":\"veo31-fast\",\"generatorMode\":\"text-to-video\",\"aspectRatio\":\"16:9\",\"durationSeconds\":8,\"modelOptions\":null,\"variantKey\":null,\"credits\":20,\"listCredits\":20,\"hasPromotion\":false,\"promotionLabel\":null,\"promotionStartsAt\":null,\"promotionEndsAt\":null,\"sourceType\":\"market_catalog\",\"sourceUpdatedAt\":\"2026-05-15\"}",
"note": null,
"created_at": "2026-04-05T13:27:59.824Z"
}
],
"pagination": { "limit": 20, "offset": 0, "total": 137 }
}
}Usage 事件字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id | string(UUID) | usage 事件 ID。 |
api_request_id | string(UUID) | 关联到原始 API 请求记录。 |
api_key_id | string | 触发事件的 API key。 |
generation_job_id | string | null | 产生扣费或退款的任务。 |
credit_transaction_id | string | null | 积分台账记录 ID。 |
event_type | "charge" | "refund" | charge 在任务入队时写入;refund 在 failed 或安全 cancelled 时写入。 |
credits_delta | number | 扣费为负数,退款为正数。 |
balance_before | number | null | 事件前钱包余额(单位:credits)。 |
balance_after | number | null | 事件后钱包余额(单位:credits)。 |
pricing_snapshot | string | null | 扣费时落库的 JSON 字符串定价快照;如需结构化字段,请先自行解析。 |
note | string | null | 运维备注,可为 null。 |
created_at | string(ISO-8601) | 事件时间。 |
pagination.total 是当前查询条件下的总记录数,而非当前页条数。
下载生成资产
curl -L "https://your-domain.com/api/v1/assets/510522c3-f7fb-4265-82ae-471f12aea62b" \
-H "Authorization: Bearer visioart_your_api_key" \
-o output.mp4常见错误码
VisioArt 把创建任务的校验拆成两层:
- Schema 层(
400 invalid_request) —— 仅做字段形状、类型与格式检查。未知字段、类型不匹配、超出声明的枚举或长度、以及landingRecordId、estimatedCredits等内部字段都会在进入业务逻辑之前就被拒绝。 - 业务层(
422 invalid_generation_request) —— 依赖工作区状态与模型能力的语义检查。合法结构的请求仍可能在这里被拒绝:modelId在当前工作区未激活、modelId×generatorMode×aspectRatio×durationSeconds组合不被支持、缺少必填上传、上传 URL 不可信,或定价规则缺失。
工作区中可用的模型及其支持的选项可被管理员覆盖,因此公共 schema 不会硬编码 modelId 枚举。批量提交前可先读取 GET /api/v1/models,或把 422 invalid_generation_request 作为可重试的"请修正输入"信号。
| HTTP | Code | 含义 |
|---|---|---|
400 | ambiguous_api_key | 同一请求中发送了多个不同的 API key 凭证。 |
400 | invalid_content_length | 请求元数据中的 Content-Length 非法。 |
400 | invalid_request | JSON 请求体未通过 schema 校验(形状、类型、格式)。 |
400 | invalid_json | 请求体不是合法 JSON。 |
400 | missing_idempotency_key | 创建任务时未提供 Idempotency-Key。 |
400 | invalid_idempotency_key | Idempotency-Key 格式不合法。 |
404 | feature_disabled | 当前工作区已禁用 Developer API。 |
401 | missing_api_key | 请求里没有提供 API key。 |
401 | invalid_api_key | API key 非法、未知或不可恢复。 |
401 | api_key_disabled | API key 已被禁用。 |
401 | api_key_expired | API key 已过期。 |
401 | invalid_authorization_header | Authorization 请求头未使用 Bearer。 |
402 | insufficient_credits | 账户余额低于当前任务预估消耗。 |
403 | insufficient_scope | API key 权限范围不足。 |
409 | idempotency_conflict | 同一个幂等 key 被不同请求体复用。 |
409 | generation_not_cancellable | 任务已经离开 VisioArt 本地可取消窗口,无法再被安全取消。 |
413 | body_too_large | 请求体超出当前大小限制。 |
415 | unsupported_media_type | 该接口只接受 JSON。 |
422 | invalid_generation_request | 请求形状合法,但解析后的生成意图不受支持(未激活的模型、不兼容的选项组合、不可信的上传 URL、缺失定价规则等)。 |
429 | concurrent_job_limit | 当前账户活跃中的 API 生成任务数量已达到上限。 |
429 | rate_limited | API key 请求频率超过限流阈值。 |
500 | internal_error | 路由级处理前发生了未预期的 Developer API 内部错误。 |
500 | models_read_failed | 模型目录加载失败。 |
500 | request_state_invalid | 已存储的幂等请求状态不完整,无法安全重放。 |
503 | provider_unavailable | provider 余额或可用性阻止了提交。 |
各接口专属错误
模型目录
500 models_read_failed
创建任务
400 invalid_request402 insufficient_credits409 idempotency_conflict429 concurrent_job_limit422 invalid_generation_request500 request_state_invalid503 provider_unavailable500 generation_create_failed
查询任务
400 invalid_generation_id404 generation_not_found500 generation_read_failed
取消任务
400 invalid_generation_id404 generation_not_found409 generation_not_cancellable500 generation_cancel_failed
计费边界说明
402 insufficient_credits会在新任务真正入库前返回。此时不会生成 generation ID,也不会写入扣费记录,更不需要退款记录。- 只有此前已经实际扣费、并且任务转入
failed,或者转入“仍处于本地安全可取消窗口内”的cancelled时,系统才会写入退款。 - 任务状态迁移、退款台账、developer API 的 refunded 计数,以及 refund usage 事件,都在同一条数据库事务里落库。只要本地退款持久化有任一步失败,VisioArt 就会整体回滚,避免出现“状态改了但退款没记完”的部分成功状态。
查询余额
500 credits_read_failed
查询 usage
400 invalid_query500 usage_read_failed
下载资产
400 invalid_asset_id404 asset_not_found500 asset_read_failed
权限范围
新创建的 API key 默认带有以下 scope:
{
"generation": ["create", "read", "cancel"],
"credits": ["read"],
"usage": ["read"],
"assets": ["read"],
"models": ["read"]
}如果某把 key 创建于 scoped permissions 引入之前,系统会保留向后兼容逻辑,不会因为缺失 permissions 字段而直接拒绝请求。 如果某把 key 已经携带显式 permissions 载荷,系统会严格按该载荷执行;向后兼容只适用于 scoped permissions 引入之前创建、因此根本没有持久化 permissions 字段的旧 key。
运维与对账说明
- generation 返回的
result_url指向的是 VisioArt 自己的资产 API 路由,而不是 provider 原始地址。 - 退款会同时写入用户 credits 台账与 developer API usage 事件表。
- credits 扣减、退款、generation 状态迁移以及 developer API 退款 usage 记录已经被收敛到同一条数据库事务中,从而避免出现“余额变了但任务状态没落库”的部分成功问题。
推荐接入流程
- 先读取
/models,拿到当前工作区的模型目录、可用 option 家族与价格证据。 - 批量提交前再读取
/credits/balance。 - 创建任务时始终携带唯一的
Idempotency-Key。 - 轮询
/generations/{jobId}直到任务进入终态。 - 用
/usage对账扣费与退款事件。
VisioArt 文档