Owl3D Cloud API
该 API 可
AI 编程
开始之前
- 在 app.owl3d.com 登录,
并 验 证 你 的 邮箱 地址。 - 订阅
套餐 或 购买 积分。 任务 先 使用 套餐 的 每月 积分, 再 使用 已 购买 的 积分。 试用 积分 也 可以 使用。 - 打
开 API 密钥 页面 并 创建 密钥。 页面 只 显示 密钥 一 次。
将OWL3D_API_KEY 中。
使用 API 须
export OWL3D_API_KEY="o3d_live_..."认证
| 项目 | 值 |
|---|---|
| Base URL | https://api.owl3d.com |
| 密钥格式 | o3d_live_<keyId>_<secret> |
| 认证 |
Authorization: Bearer <key> |
Bearer 的 B 要401。
每jobs:read 或 jobs:write。
请
GET /v1/jobs/{id}
curl https://api.owl3d.com/v1/jobs/job_... \
-H "Authorization: Bearer $OWL3D_API_KEY"{"id": "job_...", "status": "converting"}转换一个视频
下载
| 脚本 | 需求 | 运行 |
|---|---|---|
| convert.sh | bash, curl, jq, ffprobe | bash convert.sh my-video.mp4 |
| convert.py | Python 3.9+, requests, ffprobe |
python3 convert.py my-video.mp4 |
| convert.mjs | Node.js 20+, ffprobe | node convert.mjs my-video.mp4 |
convert.sh · convert.py · convert.mjs
curl -O https://www.owl3d.com/docs/api/convert.sh
bash convert.sh my-video.mp4脚本
流程
- 读取
文件 信息 并生成 指纹。 POST /v1/estimates:获取 报价。 不 会 扣费。 POST /v1/jobs:确认 报价。 这 会 预留 积分。 - 将
每 个 分片 PUT到它 的 上传 URL, 然后 POST /v1/jobs/{id}/upload-complete。 - 每 15 秒轮询
GET /v1/jobs/{id}。 GET /v1/jobs/{id}/result:获取 下载 链接。 链接 有 效 15 分钟, 且 只 能 用 GET。
先POST /v1/jobs。
错误
大多数error 是
| 状态 | 含义 |
|---|---|
400 |
请bad_fingerprint |
401 |
没有 |
402 |
short_of_credits: |
403 |
insufficient_scope, |
404 |
no_job。 |
409 |
状态not_uploading 或 endpoint_exists |
410 |
输出insufficient_credits_expired: |
429 |
某 |
重试
- 收到
429时,等 待 Retry-After秒,再 发送 相同 的 请求。 - 收到
5xx或网络 错误 时, 退避 重试, 间隔 从 1 秒 增加 到 60 秒。 - 收到
其他 4xx时,请 修正 请 求。
curl -i https://api.owl3d.com/v1/jobs/job_unknown \
-H "Authorization: Bearer $OWL3D_API_KEY"{"error": "no_job"}限制
| 限制 | 值 | 响 |
|---|---|---|
| 进行 |
账户 |
429 concurrency_limit、Retry-After: 15 |
| 请 |
每 |
429、Retry-After: 60 |
| 突 |
每 |
429 throttled、Retry-After: 1 |
| 每 |
每 |
429 daily_credit_cap, |
| 有 |
每 |
拒绝 |
| 输入 | 100 GB、 |
报价 |
| 容器 |
MP4, MOV, MKV, M4V | 报价 |
429 concurrency_limit 的scope 为 api(账户account(账户key(此
{
"error": "concurrency_limit",
"scope": "api",
"limit": 10,
"inProgress": 10
}路由
| 方法 |
范围 | 用 |
|---|---|---|
POST /v1/estimates |
jobs:write |
报价 |
POST /v1/jobs |
jobs:write |
预留estimateId,filename 和 sizeBytes(先 |
GET /v1/jobs/{id}/upload |
jobs:read |
上done、missing 和parts URL |
POST /v1/jobs/{id}/upload-complete |
jobs:write |
提交 ETag 并 |
GET /v1/jobs/{id} |
jobs:read |
状态、 |
POST /v1/jobs/{id}/cancel |
jobs:write |
取消 |
POST /v1/jobs/{id}/resume |
jobs:write |
补充积insufficient_credits 的 |
GET /v1/jobs/{id}/result |
jobs:read |
下载 |
报价
POST /v1/estimates 给
| 字段 | 值 |
|---|---|
name、size |
文 |
durationSeconds、width、height、fps |
用 |
codec |
H.264、HEVC、AV1、VP9 之一 |
bitDepth、chroma |
从chroma 为 4:2:0 |
fingerprint |
{size, headSha256, tailSha256, edgeBytes} |
edgeBytes为 4194304;文件 更 小时, 则 为 文件 大小。 headSha256和tailSha256是文件 前 edgeBytes字节与 最后 edgeBytes字节的 哈希。
响"ok": false 表示reason。credits.shortBy 大于 0 表示credits.fromPlan、credits.fromTrial 和 credits.fromPurchased 表示
POST /v1/estimates
curl https://api.owl3d.com/v1/estimates \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-video.mp4",
"size": 104857600,
"durationSeconds": 120,
"width": 1920, "height": 1080, "fps": 24,
"codec": "H.264", "bitDepth": 8, "chroma": "4:2:0",
"fingerprint": {
"size": 104857600,
"headSha256": "<SHA-256 of the first 4194304 bytes>",
"tailSha256": "<SHA-256 of the last 4194304 bytes>",
"edgeBytes": 4194304
}
}'{
"ok": true,
"id": "est_...",
"credits": {
"total": 60,
"fromPlan": 60,
"fromTrial": 0,
"fromPurchased": 0,
"shortBy": 0
},
"etaMinutes": 6,
"hdr": {"detected": false},
"output": {"format": "FULL_SBS", "width": 3840, "height": 1080}
}任务
以 {"estimateId": "est_..."} 调用 POST /v1/jobs,id 和upload.partSize 和 upload.parts 的 URL。
输出选项
POST /v1/jobs 也output: {layout, max_height}。
layout:full_sbs(默认)。max_height:"source"(默认)、2160或1080。
POST /v1/jobs
curl https://api.owl3d.com/v1/jobs \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{"estimateId": "est_...", "output": {"layout": "full_sbs", "max_height": "source"}}'{
"id": "job_...",
"status": "uploading",
"upload": {
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete"
}
}先上传
发送 POST /v1/jobs 时estimateId。
| 字段 | 值 |
|---|---|
filename |
文.mp4、.mov、.mkv 或 .m4v 结尾 |
sizeBytes |
文件 |
output |
可选。 |
- 余额
必须 够 支付 最 低 价格。 否则 返 回 402 short_of_credits,也 不 会 创建 任务。 201响应 另外 有 reservedCredits和"priceAfterUpload": true。- 上
传后, 服务 器 读取 文件 并 决定 价格。 - 如果
服务器 无法 转换 这个 文件, 任务 会 变成 failed。不 会 扣费, 文件 也 会 删除。
HDR10 视频400 hdr_needs_estimate。
POST /v1/jobs (upload first)
curl https://api.owl3d.com/v1/jobs \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"filename\": \"my-video.mp4\", \"sizeBytes\": $(wc -c < my-video.mp4)}"{
"id": "job_...",
"status": "uploading",
"upload": {
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete"
},
"reservedCredits": 15,
"priceAfterUpload": true
}积分不足
价格insufficient_credits。
GET /v1/jobs/{id}会显示 shortBy(要补充 的 积分)、 neededCredits、deleteAt和resumeUrl。- 补充积
分后, 发送 POST /v1/jobs/{id}/resume。不 要 重新 上 传 文件。 - 余额
仍 不 够 时, resume 返 回 402 short_of_credits并附带 shortBy。 - 在
deleteAt(24 小时)前 没有 resume, 任务 会 变成 failed,代码 是 insufficient_credits_expired。文件 会 删除。
POST /v1/jobs/{id}/resume
curl -X POST https://api.owl3d.com/v1/jobs/job_.../resume \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"status": "queued"
}{
"error": "short_of_credits",
"shortBy": 120,
"neededCredits": 450,
"deleteAt": "2026-11-04T09:00:00.000Z"
}上传
- 将
文件 切成 每 片 upload.partSize字节的 分片。 第 1 片 从 字节 0 开始。 - 将
每 个 分片 PUT到upload.parts中对 应 的 URL。 保留 每 个 响应 的 ETag头,连同 引号。 - 以
{"etags": [...]}调用POST /v1/jobs/{id}/upload-complete,ETag 按 分片 顺序排列。
每partSize 字节,Content-Length。
上
- 调用
GET /v1/jobs/{id}/upload。 - 读取
done。每 一 项 含 partNumber、etag和size。 - 读取
missing。它 列出 分片 编号。 - 将
每 个 缺少 的 分片 上 传到 parts[partNumber - 1]。这些 URL 有 效 1 小时。 - 按
分片 顺序带上 所有 ETag 完成 上传。 使用 同 一 个 文件。
请
PUT upload.parts[n] · POST /v1/jobs/{id}/upload-complete
split -b 67108864 my-video.mp4 part_
curl -sS -D - -o /dev/null -X PUT --upload-file part_aa "<upload.parts[0]>" | grep -i '^etag'
curl -sS -D - -o /dev/null -X PUT --upload-file part_ab "<upload.parts[1]>" | grep -i '^etag'
curl https://api.owl3d.com/v1/jobs/job_.../upload-complete \
-H "Authorization: Bearer $OWL3D_API_KEY" \
-H "Content-Type: application/json" \
-d '{"etags": ["\"<etag of part 1>\"", "\"<etag of part 2>\""]}'{"id": "job_...", "status": "queued"}GET /v1/jobs/{id}/upload
curl https://api.owl3d.com/v1/jobs/job_.../upload \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"partSize": 67108864,
"parts": ["https://...", "https://..."],
"completeUrl": "/v1/jobs/job_.../upload-complete",
"done": [{"partNumber": 1, "etag": "\"...\"", "size": 67108864}],
"missing": [2]
}任务状态
GET /v1/jobs/{id} 给
status |
含义 |
|---|---|
uploading |
任务 |
queued |
任务converting 回到 queued |
converting |
progress 从 0 到 1 |
delayed |
由 |
insufficient_credits |
价格shortBy 积分后 |
done |
完成。result 含 |
failed |
error 含 code。 |
cancelled |
已 |
GET /v1/jobs/{id}
curl https://api.owl3d.com/v1/jobs/job_... \
-H "Authorization: Bearer $OWL3D_API_KEY"{
"id": "job_...",
"status": "converting",
"progress": 0.42,
"etaSeconds": 310
}结果
GET /v1/jobs/{id}/result 为 done 的GET。410。
GET /v1/jobs/{id}/result
curl https://api.owl3d.com/v1/jobs/job_.../result \
-H "Authorization: Bearer $OWL3D_API_KEY"
curl -o output.mp4 "<url>"{
"url": "https://...",
"filename": "...",
"sizeBytes": 209715200,
"expiresInS": 900
}取消
POST /v1/jobs/{id}/cancel 会progress,
POST /v1/jobs/{id}/cancel
curl -X POST https://api.owl3d.com/v1/jobs/job_.../cancel \
-H "Authorization: Bearer $OWL3D_API_KEY"{"id": "job_...", "status": "cancelled"}