跳到正文

AI 视频

文生视频生成,支持状态轮询与取消。

1. 概览

基础路径: https://api.infrai.cc/v1/video
鉴权头: Authorization: Bearer $INFRAI_API_KEY
bash
# Call any /v1/video capability over raw HTTP — no SDK to install.
# curl:
curl https://api.infrai.cc/v1/video/... \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json"

2. 方法 (7)

2.1video.generate

POST /v1/video/generate

启动一个文生视频任务。

参数

名称类型必填说明
promptstring
必填
目标视频的文本描述。
reference_imagestring可选可选参考图像 URL。
duration_secondsnumber可选片段时长(秒)。
1–60default: 5
aspect_ratio"16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"可选宽高比。
default: "16:9"
resolution"720p" | "1080p" | "4k"可选输出分辨率(720p/1080p/4k);按供应商能力门控。
default: "720p"
modelstring可选路由模式(auto / cheapest / smartest)让 infrai 自动选型,或直接指定模型 id 以锁定(如 "kling-v2"、"wan-t2v")。省略即 auto。
idempotency_keystring可选可选去重 key;相同重试将返回同一结果。

返回

VideoJob { job_id, state, video_url?, thumbnail_url?, error? }
名称类型说明
job_idstringasync job的唯一标识符
pattern: ^vid_[A-Za-z0-9]{20,}$
state"queued" | "running" | "succeeded" | "failed" | "cancelled" | "expired"当前生命周期状态
modelstring用于生成的模型标识符
vendorstring处理此请求的供应商
promptstring内容生成的文本提示
duration_secondsinteger生成视频时长(秒)
≥ 1
aspect_ratio"16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"生成的图片或视频的宽高比(如 16:9)
video_urlstring | null生成的视频文件 URL
thumbnail_urlstring | null视频缩略图 URL
cost_usdnumber | null本次操作费用(美元)
≥ 0
created_atstring资源创建时间(ISO 8601)
format: date-time
finished_atstring | nullISO 8601 时间戳:the job finished(ISO 8601)
format: date-time
retention_daysinteger | nulldays to retain this resource数量
≥ 0
parent_job_idstring | null衍生此作业的源作业(通过 video.extend / video.upscale / webhook 重跑派生);原始生成作业为 null。
pattern: ^vid_[A-Za-z0-9]{20,}$
errorobject供应商/网关错误详情;仅在 state 为 failed 时存在。
error.codestring来自 registry.yaml 的稳定标识符。
error.http_statusintegerWebhook 投递尝试的 HTTP 状态码
400–599
error.messagestring可读提示。
error.docs_urlstring此错误码的文档 URL
format: uri
error.code_detailstring子分类(如钱包上限原因)。
error.retryableboolean错误是否可重试
error.retry_after_msinteger建议重试延迟(毫秒)
≥ 0
error.paramstring验证失败的参数(如适用)。
error.trace_idstring分布式追踪标识符
error.request_idstring服务端分配的追踪请求标识符
metadataobject本次生成的成本/供应商/模型披露(成本透明契约面);选定供应商后存在。
metadata.request_idstringUUID v7。
metadata.trace_idstring分布式追踪标识符
metadata.timestampstring数据点的 Unix 时间戳
format: date-time
metadata.latency_msinteger操作延迟(毫秒)
≥ 0
metadata.entry_formany入口格式(rest、mcp、sdk)
metadata.cost_usdnumber此操作成本(美元)
≥ 0
metadata.cost_cnynumber此请求成本(人民币)
≥ 0
metadata.vendorstring适配器名称;引用 VendorRegistry。
metadata.vendor_region"china" | "western"处理此请求的供应商区域
metadata.markup_pct0 | 0.05供应商成本之上的加价百分比
metadata.cache_layer"none" | "l1_hit" | "l1_miss" | "l2_hit" | "batch"服务此响应的缓存层
metadata.failover_infoobject使用不同供应商时的故障转移详情
metadata.failover_info.primary_vendorstring尝试调用的主供应商
metadata.failover_info.actual_vendorstring实际处理请求的供应商(故障转移后)
metadata.failover_info.primary_modelstring尝试调用的主模型
metadata.failover_info.actual_modelstring实际处理请求的模型(故障转移后)
metadata.failover_info.cost_at_primarynumber主供应商成本(美元)
≥ 0
metadata.failover_info.cost_at_actualnumber实际供应商成本(美元)
≥ 0
metadata.failover_info.cost_multipliernumber故障转移导致的成本倍数
≥ 0
metadata.failover_info.failover_reason"VENDOR_TIMEOUT" | "VENDOR_DOWN" | "RATE_LIMIT_VENDOR" | "VENDOR_AUTH_ERROR"故障转移原因
metadata.failover_info.fallback_chain_depthinteger已遍历的故障转移链深度
≥ 1
metadata.edge_popstring服务此请求的地理 PoP。
metadata.worker_idstring处理此请求的 Worker 进程标识符
metadata.idempotent_replayboolean为 true 表示此次写入复用了先前的幂等结果(Idempotency-Key 重放)。由网关设置;SDK 必须从 metadata 读取,而不是读取 header。

示例

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/video/generate \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "hello"}'

2.2video.status

GET /v1/video/status/{id}

轮询视频任务的状态。

参数

名称类型必填说明
idstring
必填
任务标识。

返回

VideoJob
名称类型说明
job_idstringasync job的唯一标识符
pattern: ^vid_[A-Za-z0-9]{20,}$
state"queued" | "running" | "succeeded" | "failed" | "cancelled" | "expired"当前生命周期状态
progress_pctinteger | null异步操作进度百分比(0-100)
0–100
eta_secondsinteger | null预估完成耗时(秒)
≥ 0
current_stepstring | null当前处理步骤的描述

示例

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/video/status/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.3video.cancel

POST /v1/video/cancel/{id}

取消正在运行的视频任务。

参数

名称类型必填说明
idstring
必填
任务标识。

返回

{ ok: boolean }
名称类型说明
job_idstringasync job的唯一标识符
pattern: ^vid_[A-Za-z0-9]{20,}$
state"queued" | "running" | "succeeded" | "failed" | "cancelled" | "expired"当前生命周期状态
modelstring用于生成的模型标识符
vendorstring处理此请求的供应商
promptstring内容生成的文本提示
duration_secondsinteger生成视频时长(秒)
≥ 1
aspect_ratio"16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"生成的图片或视频的宽高比(如 16:9)
video_urlstring | null生成的视频文件 URL
thumbnail_urlstring | null视频缩略图 URL
cost_usdnumber | null本次操作费用(美元)
≥ 0
created_atstring资源创建时间(ISO 8601)
format: date-time
finished_atstring | nullISO 8601 时间戳:the job finished(ISO 8601)
format: date-time
retention_daysinteger | nulldays to retain this resource数量
≥ 0
parent_job_idstring | null衍生此作业的源作业(通过 video.extend / video.upscale / webhook 重跑派生);原始生成作业为 null。
pattern: ^vid_[A-Za-z0-9]{20,}$
errorobject供应商/网关错误详情;仅在 state 为 failed 时存在。
error.codestring来自 registry.yaml 的稳定标识符。
error.http_statusintegerWebhook 投递尝试的 HTTP 状态码
400–599
error.messagestring可读提示。
error.docs_urlstring此错误码的文档 URL
format: uri
error.code_detailstring子分类(如钱包上限原因)。
error.retryableboolean错误是否可重试
error.retry_after_msinteger建议重试延迟(毫秒)
≥ 0
error.paramstring验证失败的参数(如适用)。
error.trace_idstring分布式追踪标识符
error.request_idstring服务端分配的追踪请求标识符
metadataobject本次生成的成本/供应商/模型披露(成本透明契约面);选定供应商后存在。
metadata.request_idstringUUID v7。
metadata.trace_idstring分布式追踪标识符
metadata.timestampstring数据点的 Unix 时间戳
format: date-time
metadata.latency_msinteger操作延迟(毫秒)
≥ 0
metadata.entry_formany入口格式(rest、mcp、sdk)
metadata.cost_usdnumber此操作成本(美元)
≥ 0
metadata.cost_cnynumber此请求成本(人民币)
≥ 0
metadata.vendorstring适配器名称;引用 VendorRegistry。
metadata.vendor_region"china" | "western"处理此请求的供应商区域
metadata.markup_pct0 | 0.05供应商成本之上的加价百分比
metadata.cache_layer"none" | "l1_hit" | "l1_miss" | "l2_hit" | "batch"服务此响应的缓存层
metadata.failover_infoobject使用不同供应商时的故障转移详情
metadata.failover_info.primary_vendorstring尝试调用的主供应商
metadata.failover_info.actual_vendorstring实际处理请求的供应商(故障转移后)
metadata.failover_info.primary_modelstring尝试调用的主模型
metadata.failover_info.actual_modelstring实际处理请求的模型(故障转移后)
metadata.failover_info.cost_at_primarynumber主供应商成本(美元)
≥ 0
metadata.failover_info.cost_at_actualnumber实际供应商成本(美元)
≥ 0
metadata.failover_info.cost_multipliernumber故障转移导致的成本倍数
≥ 0
metadata.failover_info.failover_reason"VENDOR_TIMEOUT" | "VENDOR_DOWN" | "RATE_LIMIT_VENDOR" | "VENDOR_AUTH_ERROR"故障转移原因
metadata.failover_info.fallback_chain_depthinteger已遍历的故障转移链深度
≥ 1
metadata.edge_popstring服务此请求的地理 PoP。
metadata.worker_idstring处理此请求的 Worker 进程标识符
metadata.idempotent_replayboolean为 true 表示此次写入复用了先前的幂等结果(Idempotency-Key 重放)。由网关设置;SDK 必须从 metadata 读取,而不是读取 header。

示例

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/video/cancel/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id": "sample"}'

2.4video.get

GET /v1/video/get/{id}

获取视频任务的完整详情(状态、视频地址、时长、分辨率、厂商、模型等)。

参数

名称类型必填说明
idstring
必填
任务标识。

返回

VideoJob { job_id, state, video_url?, thumbnail_url?, duration_seconds, resolution, vendor, model, error? }
名称类型说明
job_idstringasync job的唯一标识符
pattern: ^vid_[A-Za-z0-9]{20,}$
state"queued" | "running" | "succeeded" | "failed" | "cancelled" | "expired"当前生命周期状态
modelstring用于生成的模型标识符
vendorstring处理此请求的供应商
promptstring内容生成的文本提示
duration_secondsinteger生成视频时长(秒)
≥ 1
aspect_ratio"16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"生成的图片或视频的宽高比(如 16:9)
video_urlstring | null生成的视频文件 URL
thumbnail_urlstring | null视频缩略图 URL
cost_usdnumber | null本次操作费用(美元)
≥ 0
created_atstring资源创建时间(ISO 8601)
format: date-time
finished_atstring | nullISO 8601 时间戳:the job finished(ISO 8601)
format: date-time
retention_daysinteger | nulldays to retain this resource数量
≥ 0
parent_job_idstring | null衍生此作业的源作业(通过 video.extend / video.upscale / webhook 重跑派生);原始生成作业为 null。
pattern: ^vid_[A-Za-z0-9]{20,}$
errorobject供应商/网关错误详情;仅在 state 为 failed 时存在。
error.codestring来自 registry.yaml 的稳定标识符。
error.http_statusintegerWebhook 投递尝试的 HTTP 状态码
400–599
error.messagestring可读提示。
error.docs_urlstring此错误码的文档 URL
format: uri
error.code_detailstring子分类(如钱包上限原因)。
error.retryableboolean错误是否可重试
error.retry_after_msinteger建议重试延迟(毫秒)
≥ 0
error.paramstring验证失败的参数(如适用)。
error.trace_idstring分布式追踪标识符
error.request_idstring服务端分配的追踪请求标识符
metadataobject本次生成的成本/供应商/模型披露(成本透明契约面);选定供应商后存在。
metadata.request_idstringUUID v7。
metadata.trace_idstring分布式追踪标识符
metadata.timestampstring数据点的 Unix 时间戳
format: date-time
metadata.latency_msinteger操作延迟(毫秒)
≥ 0
metadata.entry_formany入口格式(rest、mcp、sdk)
metadata.cost_usdnumber此操作成本(美元)
≥ 0
metadata.cost_cnynumber此请求成本(人民币)
≥ 0
metadata.vendorstring适配器名称;引用 VendorRegistry。
metadata.vendor_region"china" | "western"处理此请求的供应商区域
metadata.markup_pct0 | 0.05供应商成本之上的加价百分比
metadata.cache_layer"none" | "l1_hit" | "l1_miss" | "l2_hit" | "batch"服务此响应的缓存层
metadata.failover_infoobject使用不同供应商时的故障转移详情
metadata.failover_info.primary_vendorstring尝试调用的主供应商
metadata.failover_info.actual_vendorstring实际处理请求的供应商(故障转移后)
metadata.failover_info.primary_modelstring尝试调用的主模型
metadata.failover_info.actual_modelstring实际处理请求的模型(故障转移后)
metadata.failover_info.cost_at_primarynumber主供应商成本(美元)
≥ 0
metadata.failover_info.cost_at_actualnumber实际供应商成本(美元)
≥ 0
metadata.failover_info.cost_multipliernumber故障转移导致的成本倍数
≥ 0
metadata.failover_info.failover_reason"VENDOR_TIMEOUT" | "VENDOR_DOWN" | "RATE_LIMIT_VENDOR" | "VENDOR_AUTH_ERROR"故障转移原因
metadata.failover_info.fallback_chain_depthinteger已遍历的故障转移链深度
≥ 1
metadata.edge_popstring服务此请求的地理 PoP。
metadata.worker_idstring处理此请求的 Worker 进程标识符
metadata.idempotent_replayboolean为 true 表示此次写入复用了先前的幂等结果(Idempotency-Key 重放)。由网关设置;SDK 必须从 metadata 读取,而不是读取 header。

示例

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/video/get/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.5video.delete

DELETE /v1/video/delete/{id}

删除指定视频任务及其产物(幂等写)。

参数

名称类型必填说明
idstring
必填
任务标识。
idempotency_keystring可选可选去重 key;相同重试将返回同一结果。

返回

{ ok: boolean }
名称类型说明
job_idstring | null受影响的作业;批量操作(delete_all)为 null。
pattern: ^vid_[A-Za-z0-9]{20,}$

示例

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X DELETE https://api.infrai.cc/v1/video/delete/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.6video.download_url

GET /v1/video/download_url/{id}

为指定视频任务签发带过期时间的临时下载链接。

参数

名称类型必填说明
idstring
必填
任务标识。

返回

{ url: string, expires_at: string }
名称类型说明
job_idstringasync job的唯一标识符
pattern: ^vid_[A-Za-z0-9]{20,}$
urlstringInfrai 托管的带签名、有时限的下载 URL。
format: uri
expires_atstring资源或令牌过期时间(ISO 8601)
format: date-time
size_bytesinteger | null资源大小(字节)
≥ 0
content_typestring | null对象的 MIME 类型

示例

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/video/download_url/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.7video.capabilities

GET /v1/video/capabilities

查询各视频厂商支持的模型、分辨率、最大时长及扩展/超分能力。

返回

VideoCapabilities { vendors: Array<{ vendor, models, resolutions, max_duration_seconds, supports_extend, supports_upscale }> }
名称类型说明
modelsobject[]提供的视频模型,每个定价(供应商、模型)行一个。
models[].vendorstring-
models[].modelstring-
models[].regionstring | null-
models[].max_secondsinteger | null供应商适配器强制的最大生成时长(超过则 DURATION_EXCEEDED);适配器不存在时为 null。
≥ 1
models[].image_to_videoboolean | null供应商是否支持图生视频;适配器不存在时为 null。
resolutions("720p" | "1080p" | "4k")[]支持的分辨率键(也是 resolution_multiplier 的键)。
resolution_multiplierobject按分辨率的成本轴乘数(如 720p=1.0、1080p=2.0、4k=4.0)。

示例

一次性前置(每个范例都假定已完成):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/video/capabilities \
  -H "Authorization: Bearer $INFRAI_API_KEY"
高级:指定 vendor

默认情况下 infrai 会把每次调用智能路由到最佳可用供应商——无需自己挑选 vendor。作为高级逃生口,本能力支持可选的 vendor 入参以锁定某个供应商。本能力当前所有可用 vendor 可通过该能力 id 对应的 discovery 端点实时获取——参见 discovery API

GET /v1/discovery/{capability}

video.generate

3. 全部能力

本模块全部已路由能力——完整的对外 REST 契约。上方方法是带讲解的入门示例,此表是完整参考。

video.cancelPOST /v1/video/cancel/{id}

Cancel an in-progress video generation job.

参数 (3)
名称类型必填说明
idstring必填Path parameter.
job_idstring必填Id of the video job to cancel.
idempotency_keystring | null可选Client-provided idempotency key; prevents duplicate execution on retry
video.capabilitiesGET /v1/video/capabilities

Query each video provider's supported models, resolutions, max duration, and extend/upscale capabilities.

无请求参数。

video.deleteDELETE /v1/video/delete/{id}

Delete a video job and its artifacts (idempotent write).

参数 (1)
名称类型必填说明
idstring必填Path parameter.
video.download_urlGET /v1/video/download_url/{id}

Issue a time-limited, expiring download URL for a video job's output.

参数 (1)
名称类型必填说明
idstring必填Path parameter.
video.generatePOST /v1/video/generate

Generate a video from a text or image prompt asynchronously (idempotent).

参数 (12)
名称类型必填说明
promptstring必填Text prompt for content generation
modelstring | null可选Model selector. A specific video model id (e.g. 'wan-t2v'), OR a routing MODE: 'auto' (default, balanced value), 'cheapest' (lowest USD/s), 'smartest' (flagship). Null = auto.
resolution"720p" | "1080p" | "4k"可选Output resolution spec axis. Gated per-vendor. (SSOT: enums/VideoResolution)
default: "720p"
duration_secondsinteger可选Duration of generated video in seconds
1–60default: 5
aspect_ratio"16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"可选Aspect ratio for generated images or video (e.g. 16:9)
default: "16:9"
seedinteger | null可选Random seed for deterministic generation
negative_promptstring | null可选Negative prompt for excluding unwanted content
reference_imagestring | null可选URL or base64 for image-to-video.
vendorstring | null可选Vendor that handled or will handle this request
webhook_urlstring | null可选Optional callback URL; declares an async delivery target at submit time (events from VideoEventType). Equivalent to a video.webhook.subscribe for this job.
format: uri
idempotency_keystring | null可选Client-provided idempotency key; prevents duplicate execution on retry
storeboolean可选Opt in to RETAIN the produced asset/record in Infrai's own store (default false = stateless passthrough: process, return inline, keep nothing). When true, Infrai persists the asset, bills a self-hosted storage line item and applies a retention TTL — and only then do the *.list/get/delete read caps see it.
default: false
video.getGET /v1/video/get/{id}

Retrieve a video job's full details (status, video URL, duration, resolution, provider, model).

参数 (1)
名称类型必填说明
idstring必填Path parameter.
video.statusGET /v1/video/status/{id}

Query a video generation job's status and output URL.

参数 (1)
名称类型必填说明
idstring必填Path parameter.

4. 完整示例

本模块的生产级端到端范例:先一次性配置,再运行业务流程,尽量覆盖本模块的多数 API。

单文件可运行 Python 程序(仅标准库、无 SDK):拷贝后填入 INFRAI_API_KEY 运行,即可按真实业务流逐步体验本模块核心 API——每一步都真实调用并计费,后续步骤复用前一步返回的真实字段。12 行 helper 就是全部集成代码。

python
#!/usr/bin/env python3
"""Infrai · ai-video — runnable real-app example (single file, zero deps).

Copy this file, set your key, run it: every step is a REAL call to
api.infrai.cc, billed at the real (tiny) per-call price, printing the
live JSON response. Get a key at https://infrai.cc/login (Google/
GitHub sign-in grants $2 free credit); add funds at
https://infrai.cc/billing. No SDK — the 12-line helper below is the
entire integration."""
import json
import os
from urllib import error, request

KEY = os.environ.get("INFRAI_API_KEY") or "ifr_..."  # <- your key
BASE = "https://api.infrai.cc"


# Same raw HTTPS POST/GET as every per-method example on this page —
# wrapped once for reuse. There is nothing else to it: no SDK.
def infrai(method, path, body=None):
    req = request.Request(
        BASE + path, method=method,
        data=json.dumps(body).encode() if body is not None else None,
        headers={"Authorization": f"Bearer {KEY}",
                 "Content-Type": "application/json"})
    try:
        with request.urlopen(req, timeout=60) as r:
            return json.loads(r.read())
    except error.HTTPError as e:
        return json.loads(e.read())


def show(label, resp):
    print(f"\n== {label} ==")
    print(json.dumps(resp, indent=2, ensure_ascii=False))
    return resp


# 1) video.generate — POST /v1/video/generate · Generate a video from a text or image prompt asynchronously (idempotent).  # NOTE: non-trivial real cost
r1 = show("video.generate", infrai("POST", "/v1/video/generate", {"prompt":"a timelapse of a city skyline at dusk","resolution":"1080p","duration_seconds":5}))

# 2) video.status — GET /v1/video/status/{id} · Query a video generation job's status and output URL.
id_2 = (r1.get("data") or {}).get("job_id") or ""
r2 = show("video.status", infrai("GET", f"/v1/video/status/{id_2}"))