鲸鱼API

接口文档

兼容 OpenAI 协议的视频生成接口。拿一把 API 密钥,就能用你熟悉的 SDK 直接调。

想要一份能离线看、能贴进自己文档、能喂给 AI 的?

下载 Markdown 版 (.md 文件,点一下直接存到「下载」文件夹)
或在线打开看全文 (不想存文件就走这个)

地址固定不变(/api-docs.md),内容与本页一致,换版不换链接。 手机上如果点了没反应,多半是被微信/QQ 的内置浏览器拦了 —— 点右上角「⋯」选「在浏览器中打开」再点一次。

不想写代码?可以直接用「字字动画」的两个插件(视频 + 出图),装上就能在软件里选型号出片 —— 见 第十二节,装法写在 飞书教程 里。 那份教程还包含鲸鱼AI 软件的完整用法,不用懂任何代码。

一、准备:拿密钥

  1. 登录 控制台。账号由我们开通;充值请加微信 XYSM2015。
  2. 左侧 API 密钥 → 添加密钥 → 复制 sk- 开头那串。
  3. 按下面的例子调用即可。

密钥就是你的身份,谁拿到都能花你的余额。别发到群里,也别写进前端代码。

二、Base URL 与接口地址

所有接口都在这个地址下(带 /v1,用 OpenAI SDK 时填这个作 base_url):

Base URL: https://xyjingyuapi.com/v1

POST /videos                  提交一个视频任务
GET  /videos/{id}             查进度(完成后这里会给 artifact.url)
GET  /videos/{id}/content     取成片(返回 mp4 字节流;要带 Authorization,路径没有扩展名)
GET  /models                  当前可用的型号列表

取片只有 /content 这一条路。查进度时响应里的 artifact.url 就是它(相对路径,拼上 Base URL 即可)—— 不要用任何其它地址去下载:上游的内部存储链接需要他们自己的密钥、还有时效, 直接访问会 404。详见第三小节末尾那张"四种写法一定会失败"。

成片在我们这里保留 24 小时(从生成完成时算)。24 小时内随时可以重复下载、 支持断点续传(Range 请求回 206),下载多少次都不再扣费。

超过 24 小时再取会返回 410(gone):片子已经清掉了。 请在生产代码里"出片即取"—— 生成完成后立刻下载并转存到你自己的存储, 别把它当永久地址用。真要补取历史成片,把任务号发给运营,不要反复重试。

OpenAI SDK 里就这样填:

from openai import OpenAI
client = OpenAI(base_url="https://xyjingyuapi.com/v1", api_key="sk-你的密钥")

下面所有例子都写成完整地址(https://xyjingyuapi.com/v1/videos), 照着复制就能跑,不用自己拼。

出图(图片生成)也在本站:POST /v1/images/generations, 型号见第七节(gpt-image-2 / gpt-image-2.5 / banana-2.1), 用同一把密钥、同一个 Base URL,不用另开账号。

(主站 https://jingyumanju.com/v1 也仍然能出图,那是给软件用的。 两边各自独立:型号清单、售价、上下架都各管各的,接口站这边**直连上游**, 不经过主站 —— 所以别拿一边的型号名去另一边调用,可能那边没有这个型号。)

三、快速开始

三步:提交 → 查进度 → 取片。下面每步给一个能直接跑的最小例子, 完整可跑的 Python(含断点续传与完整性校验)在 附录 A。

1. 提交任务

curl https://xyjingyuapi.com/v1/videos \
  -H "Authorization: Bearer sk-你的密钥" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nh-2.5-t-720p",
    "prompt": "镜头缓慢推近,人物微微转头看向镜头,光影自然流动",
    "size": "720x1280",
    "images": ["https://你的图床/人物.jpg"]
  }'

四个必填,缺一个就 400、不提交、不扣费:

字段怎么填缺了会回
model型号名原样抄第七节那张表(区分大小写,含中文括号)model_not_found
prompt画面描述,越具体越好prompt_required
size像素 "720x1280" 或比例 "9:16",两种写法都认、等价size_required
images参考图数组,公网 http(s),最多 9 张(input_reference 传首帧,单张)input_reference_required

为什么 size 必须给:不传就由通道自己决定方向 —— 要竖屏却拿到横屏,而且全程没有提示。size 和 aspect_ratio 都传时 以 aspect_ratio 为准(见第六节)。 参考图怎么填、多张为什么都生效、URL 有什么要求 —— 见第四节。

成功返回任务 id,存下来 —— 查询和取片都靠它。丢了只能重新生成(=再扣一次费):

{
  "id": "Lmvovrjyscomr9",        // ★ 后面的查询、取片都用这个 id
  "object": "video",
  "created_at": 1769900000,
  "status": "queued",
  "model": "nh-2.5-t-720p",
  "progress": 0,
  "seconds": "15"
}

2. 查进度

curl https://xyjingyuapi.com/v1/videos/任务id \
  -H "Authorization: Bearer sk-你的密钥"

status 只有四种值,别自己加判断:

status意思你该做什么
queued排队中(含"通道忙、我们正在自动重发")继续等,不要重新提交
in_progress正在出片继续等
completed出好了马上去取片(下一步)
failed终态,不会再好看 error.message;钱已全额退回,改参数重试即可

不要重复提交:每调一次 POST /v1/videos 就是一条新任务、扣一次费。 "觉得没动静"就再发一次,是最常见的多扣费原因 —— 先查进度,别猜。

3. 取成片:只有一条路

curl https://xyjingyuapi.com/v1/videos/任务id/content \
  -H "Authorization: Bearer sk-你的密钥" \
  -o 我的片子.mp4

返回的是 mp4 字节流本身(不是 JSON、也不是跳转)。地址就是进度响应里的 artifact.url —— 它是相对路径,拼上 Base URL 就能用。照它用,不要自己拼。

下完必须验完整性 —— 这是最容易忽略、也最难查的一类问题。 只判断"写入了超过 1KB",一条 8MB 的片子断在半截(比如只下了 2.6MB)也会被当成成功: 宿主打开的是一片没有索引的 mp4,表现就是"打不开 / 拉不进剪辑软件", 而日志和 API 全都写着成功。三条校验,任何一条不过都不要当成成功:

校验怎么做不过说明什么
字节数 把落盘大小和响应头 Content-Length 比;续传时按「已有 + 本次应得」算。 没下完(网络断了 / 客户端超时)。接着下即可,别重新生成。
是不是视频 前 32 字节里要有 ftyp(mp4 容器魔数)。 拿到的是错误页 / JSON(常见于把 4xx 的响应体当文件写了)。
能不能播 文件里要有 moov box(尺寸索引)。 结构不完整,播放器打不开。我们的片子 moov 在文件最尾部 (实测 8.1MB 的片子,moov 在 99.8% 处)⇒ 任何半截档都不会有它,所以这一条最能抓住"下了一半"。

特别注意:服务端没给 Content-Length 时 (分块传输、或靠关连接界定正文),提前断开很多 HTTP 库不会报错, 会安静地把半截文件交给你 —— 这时只有 moov 那一条能拦住。

现成写法见 附录 A。 下载失败不要盲目重新生成:片子已经生成好了(钱也扣了),重新生成是再扣一次。

下面这四种写法一定会失败(线上每天都有客户踩,所以单独列出来):

错在哪会看到什么为什么
拿响应里任何看起来像直链的地址去下载 404 或 403,或过几小时突然失效 那是上游内部的存储地址:需要他们的密钥、有时效、而且是别人家的域名。我们不会把它给你。
自己拼 /v1/videos/{id}/content.mp4 404 取片口就是 /content,没有扩展名。文件名靠下载时的 Content-Disposition 给(浏览器会存成 mp4)。
看到 completed 就立刻取,取一次 409 就报错退出 409 video_not_ready 产物从"生成完"到"能下载"之间还有几秒同步时间。等 3~5 秒再取一次即可,不用重新生成。
用 GET 取片时不带 Authorization 401 取片和提交一样要鉴权(否则知道 id 的人就能下别人的片子)。

四、参考图:所有视频型号都必须带(最多 9 张)

更正(2026-10-30):这一节以前写「每条任务只收 1 张参考图」, 理由是 input_reference 在协议里是单个字符串。 那个字段确实只收一个串 —— 但那是字段的限制,不是接口的限制。 多图走 images 数组,这个接口一直就收,上限 9 张, 而且全部会透到模型(实测:传 4 张,上游收到的就是 4 张)。 以前按"只收 1 张"写,客户只传了首帧、丢了几张角色参考,出片对不上还以为是模型不行。 保守写小也是撒谎,所以这里改正。

至少 1 张,最多 9 张,值是公网能访问的 http(s) 图片地址。两种字段各管一件事:

字段类型能带几张用途
images数组最多 9 张 推荐。锁人物 + 场景 + 表情等多张参考都用它,全部生效
input_reference单个字符串1 张 OpenAI Sora 标准写法,放首帧。老代码不改也能用
image / image_url字符串1 张 兼容老写法与第三方 SDK

顺序有意义:模型按你给的顺序取参考,越靠前权重越高。首帧(这一镜从哪开始) 建议放第一个。用 images 时第一个元素就是首帧。

不传会直接 400(input_reference_required),不会扣费。 我们卖的是参考生视频,没有纯文生的型号 —— 不带图就没有画面依据。

不要直接传 base64 / data: URI(input_reference_not_url)。 硬收会让任务在扣费后才失败 —— 上游拉不到图。

本地图片请先用我们的上传接口换成 URL(见下面「4.1 上传本地图片」)。 以前这里写着"我们没有转存服务",那是当时的实情,现在不必再自己挂图床了 —— 尤其是别往公共图床上传客户素材,那种服务随时会挂、也可能被别人看到。

单张参考图上限 16MB,而且不用你自己压:我们在提交前会自动把每张压到 长边 1920、约 100~250KB(JPEG 高质量,肉眼无差),再交给模型。 参考图是"定画面"用的,压缩不影响出片效果,所以你直接把原图给我们就行。 超过 16MB 会被拒收(不扣费),并告诉你是第几张。

链接要能被外网直接读到:不能是登录后才可见的地址、分享页或网盘预览页。

顺便说一句参考音频:如果你要带音频参考,只支持 WAV / MP3,且每条不超过 5 秒。 音频是辅助项,出问题我们会在提交时自动去掉重试一次,不会连累整条片子。

三种写法都认:

// ① 多张(推荐)。images 是数组,最多 9 张,全部生效
"images": [
  "https://你的图床/首帧.jpg",
  "https://你的图床/人物B.jpg",
  "https://你的图床/场景.jpg"
]

// ② 只带首帧(OpenAI Sora 标准写法)
"input_reference": "https://你的图床/首帧.jpg"

// ③ 兼容老写法 / 第三方 SDK
"image": "https://…/a.jpg"

// ①+② 一起给也没问题:两张都算,同一张重复给会自动去重

为什么 input_reference 不能传数组:这个字段在协议里定义成 单个字符串,传数组会直接 400(input_reference_not_url)。 要传多张用 images —— 别因为一个字段只收一张,就以为整个接口只收一张。

超过 9 张怎么办:只收前 9 张。要精确控制顺序,把最要紧的放前面。

不用自己压图,我们压:每张参考图在提交前会被自动压到 长边 1920、约 100~250KB(JPEG 高质量重编码,长边小于 1920 的原样不放大)。 带透明通道的 PNG、动图(GIF/WebP)原样转发,不会被转成 JPEG(那样透明会变黑底)。 实测:9 张各 1.26MB(共 11.4MB)压完每张约 105KB,整个提交 3~7 秒(多次实测 2.6 / 4.1 / 6.7 秒;不改之前是 19.5 秒,而且 15 秒就被掐断)。

仍然建议客户端超时给够:60 秒以上。慢的从来不是模型,是 "把这些图上传到我们这儿"这一段(走你自己的上行带宽);图片越大越久, 而且这是在你的网络里发生的,我们没法替你加速。

我们建议:一个分镜一般 2~4 张就够(首帧 + 主要角色 + 关键场景)。 参考图越多,模型越容易"折中",反而更容易偏。

越接近你想要的画面(构图、人物、光线)出片越准。参考图必须是图片,不要传视频链接。

4.1 上传本地图片(本地文件 → 公网 URL)

如果你手里是本地文件(软件截图、手机照片),先调一次上传,拿到 URL 再提交视频。

POST https://xyjingyuapi.com/v1/uploads
Authorization: Bearer sk-你的Key
Content-Type: application/json

{
  "filename": "ref.png",
  "content_type": "image/png",
  "data": "<图片字节的 base64>"
}

→ 200 {"object":"file","url":"https://…/ref.png","size":123456}

多张参考图直接传就行。 上面这个上传接口只是"把本地图换成 URL", 拿到 URL 后放进 images 数组,最多 9 张、全部生效(见第四节)。

五、seconds 怎么填:看型号

每个型号的时长是型号本身定好的,不需要你选。但要不要传 seconds, 取决于这个型号怎么计费 —— 下表「seconds」一列写得很清楚,照它来就行。

为什么要管得这么严:早期版本的接口会把 seconds 当成计价倍率, 客户传对了秒数反而被多收好几倍,而且接口返回 200、片子照出,月底对账才发现。 现在一律按型号的固定时长生成,秒数只用于确认,不会因为传了它多收你钱。

六、画面比例 ≠ 分辨率档位

这两个经常被混在一起问,其实是两件事:

你说的接口里是怎么给能不能改
横屏 / 竖屏画面比例(16:9 / 9:16) size(像素)或 aspect_ratio(推荐,显式) 能:同一个型号横竖都行
清楚到什么程度分辨率档位(720p / 1080p) 写在型号名里:型号名带 1080p 就是 1080p,带 720p 就是 720p 不能:换档位=换型号=换价格

为什么档位不能用参数改:价格是按型号定的。如果允许传一个 resolution=720p 去跑 1080p 的型号,那就成了"按 1080p 收钱给 720p 的片" (或者反过来白送),两边都说不清。所以档位只认型号。

像素与比例的对应(这几组一定对得上,别自己拼数字):

两个都给时以 aspect_ratio 为准。只给 size 也能用 (从宽高比推),但显式给不会推错 —— 竖屏需求被推成横屏,客户往往出了片才发现。

七、型号与价格

型号名请原样复制(区分大小写,也含中文和括号)。表里的名字与软件里、 后台里、教程里显示的是同一个 —— 换行、少一个括号都会对不上。

两种写法都认,推荐用下表这个名字:

所以:人写配置用上表的名字,程序自动发现用 /v1/models 的 id。

型号时长seconds价格计费
c-sd-2.0-1080p(巨慢!)固定 15 秒传 15(不影响计费)¥2.00按次
nh-2.5-t-720p固定 30 秒传 30(不影响计费)¥8.00按次
a-2.5-bd-t-720p固定 30 秒传 30(不影响计费)¥7.50按次
a-2.5-cd-t-720p固定 30 秒传 30(不影响计费)¥6.50按次
xf-2.5-720p固定 30 秒传 30(不影响计费)¥6.50按次
j-2.5-t-720p固定 30 秒传 30(不影响计费)¥7.00按次
S-2.5-t-720p固定 30 秒传 30(不影响计费)¥7.00按次
Seedance 2.0-720P-s固定 15 秒传 15(不影响计费)¥2.50按次
Seedance 2.5满血满参720p固定 30 秒传 30(不影响计费)¥6.50按次
minimax-h3-720p固定 15 秒传 15(不影响计费)¥0.80按次
高质量sd2.5固定 30 秒传 30(不影响计费)¥7.00按次
特价sd2.5固定 30 秒传 30(不影响计费)¥6.50按次
DB-SD-2.0固定 15 秒传 15(不影响计费)¥2.50按次
kling-v4-720-30s固定 30 秒传 30(不影响计费)¥7.00按次
re-sd-2.0-720固定 15 秒传 15(不影响计费)¥2.00按次
86-sd2.0-pro固定 15 秒传 15(不影响计费)¥2.50按次

控制台余额直接以元显示(充 10 元就是 10 元)。上表的「点」是软件里同一套计价单位, 10 点 = 1 元。每次调用按上表扣一次;失败会自动退回,不用找我们。

这张表跟着线上在售数据自动更新(每 15 分钟一次)。也可以随时拉接口,拿到的就是当前在售清单:

curl https://xyjingyuapi.com/v1/models \
  -H "Authorization: Bearer sk-你的密钥"

下架的型号不会出现;临时维护中的会出现,但带 maint: true —— 那种暂时调不通(提交会明确报错并自动退款),不是我们悄悄吞掉你的请求。

所以:先看 maint 再提交,比调完再猜省事。上表和接口是同一份数据, 都跟着线上在售每 15 分钟刷新一次。

图片型号(出图,同步返回)

出图走 POST /v1/images/generations,同步返回 (response_format 默认给 URL,也可以要 b64_json)。 必须传 size(像素或比例都行),不传会被拒 —— 我们不替你猜画幅。

型号能力单价说明
gpt-image-2文生图¥0.20 / 张快、稳,日常素材图(约 1 分钟)
gpt-image-2.5文生图¥0.25 / 张细节更好,版本更新
banana-2.1文生图¥0.40 / 张风格化更强,适合封面 / 海报

这几个型号都支持「图生图」(按你给的参考图改)。 传 image(一张公网图片地址)或上传文件,我们就会按那张图改, 而不是无视它另画一张。

一次只收 1 张:多张会明确回 400("一次只能带 1 张参考图"), 不会悄悄只取第一张就当成你要的样子。要改多张就分几次调用,每次各扣一次。

实测举例:给一张「深色背景的角色立绘」+ 提示词「保持角色不变,背景换纯白」, 出来的就是同一个角色、白色背景 —— 参考图真的起作用了。

图片按张计费:n 只能是 1,要几张就调几次。 失败自动退回,和视频一个口径。

文本型号(对话 / 写作,按 token 计费)

走标准 OpenAI 对话接口 POST /v1/chat/completions,同步返回, 你原来调 OpenAI 的代码改个 base_url 就能用。

它的计费方式和视频、图片都不一样:视频按条、图片按张, 而文本按实际用量(输入 token + 输出 token)扣。 问一句话几分钱,写一万字也才几毛 —— 不会出现"一句话扣一条片子的钱"。

型号输入价输出价适合
tt-6-luna¥2 / 百万 token¥8 / 百万 token
deepseek-v4.1-flash¥3 / 百万 token¥8 / 百万 token
tt-5.6-luna¥3 / 百万 token¥9 / 百万 token
gem-3.8-flash¥5 / 百万 token¥15 / 百万 token

输出比输入贵(各家都这样),因为生成的每个字都要算一遍。 上面是"每百万 token"的单价 —— 一篇文章通常几千 token,实际扣的是分位。

curl https://xyjingyuapi.com/v1/chat/completions \\
  -H "Authorization: Bearer sk-你的密钥" \\
  -H "Content-Type: application/json" \\
  -d '{"model":"tt-5.2",
       "messages":[{"role":"user","content":"把这句话改得更口语:此事尚需进一步商讨。"}]}'
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "choices": [ { "message": { "role": "assistant", "content": "这事儿还得再商量商量。" } } ],
  "usage": { "prompt_tokens": 28, "completion_tokens": 12, "total_tokens": 40 }
}

扣费就是照 usage 算的: prompt_tokens × 输入价 + completion_tokens × 输出价,再除以一百万。 上面这条按 tt-5.2 算约 0.00008 元(不到一分钱)。

想边生成边看(长文更明显):加 "stream": true 走 SSE 流。 流式同样按实际用量结算,不多收。

文本不占"次数":余额就是钱 —— 视频扣 2.5 元、文本扣 0.00008 元, 都从同一份余额里扣,互不影响。

八、每个型号能吃多少素材

准备素材前先看这张表:参考图 / 参考视频 / 参考音频各能吃几段、 描述词最多写多少字、出片分辨率。数字取自我们服务端的真实上限 (不是模型厂商文档里那个更宽松的数字)—— 超了会被拒绝或裁掉,按这张表准备最省事。

型号分辨率上游版本参考图参考视频参考音频提示词上限
c-sd-2.0-1080p(巨慢!)1080p—900不限
nh-2.5-t-720p720—900不限
a-2.5-bd-t-720p720p—900不限
a-2.5-cd-t-720p720—900不限
xf-2.5-720p720—900不限
j-2.5-t-720p720—900不限
S-2.5-t-720p720—900不限
Seedance 2.0-720P-s720P—900不限
Seedance 2.5满血满参720p720P—900不限
minimax-h3-720p720P—900不限
高质量sd2.5720—900不限
特价sd2.5720—900不限
DB-SD-2.0——900不限
kling-v4-720-30s——900不限
re-sd-2.0-720——900不限
86-sd2.0-pro——900不限

怎么读这张表

「上游版本」是同一款模型的第几代(900 / 903 / 933 这样)。同一个名字在上游有好几代在跑,画质、稳定性、成本都不同 —— 客户按型号名看不出区别,所以我们把这代标出来。它不是分辨率:实测同一个 903,在一个通道出 1920×1080、在另一个通道出 1256×720,出片尺寸以「分辨率」那列和实际成片为准。

参考图这一列写的是「本接口能传几张」,不是型号原生上限。 视频型号现在写 9(images 数组,见第四节)。参考视频 / 参考音频 写 0, 不是"模型不支持",是本接口还没有这两个字段。

★ 2026-10-30 更正:这里以前写 1,理由是 input_reference 只能一个字符串 —— 那是字段的限制,不是接口的限制。 多图走 images,一直就是 9 张。

提示词上限写不限的型号,我们这边不截断,但建议控制在 2000 字以内: 描述越长,模型越容易只抓住其中一部分;个别上游对超长描述会直接报错或静默截断。 真遇到描述词相关的报错,先把描述砍到 1000 字以内再试。

参考图 0 的型号:这条型号我们当前不会把你的参考图发出去(拿不到上游的参考能力), 所以写 0 —— 传了也不会生效,别以为"人物锁住了"。

这张表跟着线上下发的能力位每 15 分钟刷新一次,与 GET /v1/models 的 ref_max / prompt_max / resolution 是同一份数据。

九、常见报错

code意思怎么办
input_reference_required没传参考图加 input_reference(见第四节)
input_reference_not_url参考图不是公网地址传 https://…,不要 base64
fixed_durationseconds 与型号的固定时长不符删掉 seconds,或按上表填
seconds_out_of_range秒数超出该型号范围按上表范围传
model_not_found型号名拼错或已下架对照上表,注意大小写
size_required没传 size加 "size":"720x1280"(像素)或 "9:16"(比例)。不传不扣费
size_ambiguoussize 只写了档位名(如 "720p")—— 没有方向档位名分不出横竖屏,改写成像素或比例
size_not_supported这个型号不认这种 size 写法改用像素(1280x720 / 720x1280)或比例(16:9 / 9:16)
insufficient_quota余额不足充值是人工的,加微信 XYSM2015
authentication_error密钥不对或已删除在控制台重新建一把
generation_failed出片失败(出现在查进度的 error.code 里,status 同时是 failed)已自动全额退款,按 error.message 改一改再试
video_failed取片时这条任务已经失败,没有内容可取(409)同上;先看一次 GET /v1/videos/{id} 的 error.message
video_cancelled这条任务被取消(status 也是 failed)已全额退款;不是你的参数问题,直接重发一次
video_not_ready片子还在生成,或刚完成还在同步(取片回 409)等 3~5 秒再取一次;不要重新生成
video_not_found这个 id 不是你这把密钥下的任务(或写错了)用提交时返回的 id;我们不区分"不存在"和"不是你的"

报错都是这个形状,message 直接写清怎么改:

{
  "code": "input_reference_required",
  "message": "This model requires at least one reference image. Pass it as "input_reference": "https://…/image.jpg" (public http(s) URL)."
}

十、账单与答疑

用了上面还搞不定,把三样发我,能马上定位:

  1. 任务 id
  2. 型号名
  3. 报错原文

微信:XYSM2015(加时说一句"API",通过得快些)

十一、出图(图片生成)

本节有两种接入,别混:

· 本站(推荐):POST https://xyjingyuapi.com/v1/images/generations, 用本站的 sk- 密钥,型号 gpt-image-2 / gpt-image-2.5 / banana-2.1。 返回的是图片外链(data[0].url),直链可直接下载、外链有时效。

· 主站:https://jingyumanju.com/v1/images/generations, 用 ak_ 开头的密钥(给软件用的那条链路)。 返回的是 base64(data[0].b64_json)。

两边的型号名不是同一套,别互相套用。

协议与 OpenAI 的图片接口一致,同步返回(等出图完成才回包,通常 5~60 秒):

curl https://xyjingyuapi.com/v1/images/generations \
  -H "Authorization: Bearer sk-你的本站密钥" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-image-2","prompt":"雨夜的旧书店,暖黄灯光,电影感","size":"1024x1024"}'

本站返回的是外链(不是 base64):

{
  "created": 1793175091,
  "data": [ { "url": "https://…/20261028161158_18e2a34522c0e7e24bac.png" } ]
}

主站那条链路返回 base64(data[0].b64_json),例子见本节末尾的老示例——按你要接哪边选。

主站(ak_ 密钥)的老示例
curl https://jingyumanju.com/v1/images/generations   -H "Authorization: Bearer ak_你的密钥"   -H "Content-Type: application/json"   -d '{"model":"tt-image-2","prompt":"雨夜的旧书店,暖黄灯光,电影感","size":"16:9"}'

返回的是 base64 图片数据(不回外链,省得你还要再发一次带鉴权的下载请求):

{
  "created": 1769900000,
  "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUg..." } ],
  "id": "Lmvovrjyscomr9"
}

三个参数要点(两边都适用):

可用型号与价格随时变,以 GET /v1/models 为准 (看 supported_endpoint_types 里带 image-generation 的那几条)。 这几个图片型号都支持图生图。

10.1 出图会遇到的报错

code意思怎么办
prompt_required没传 prompt把画面描述放进去
model_not_found型号名不对或已下架先 GET /v1/models 看 capability:"image" 的 id
size_requiredsize 没传,或写法不接受传像素(1920x1088)或比例(16:9)。不传不扣费
n_not_supportedn 不是 1一次一张;要多张就多调几次(每次扣一次)
ref_not_supported这张参考图我们没法用(不是图片、或地址取不到)换一张公网能打开的图片地址,或改成直接上传文件
ref_too_many一次带了多张参考图图生图一次只收 1 张;要改多张就分几次调用(每次各扣一次)
image_failed上游没出成已自动全额退款,改改提示词重试
insufficient_quota余额不足充值请加微信 XYSM2015

十二、不想写代码?用「字字动画」插件

如果你只是想在剪辑/动画软件里生成画面,不用自己调接口 —— 我们把它做成了 字字动画的两个插件(视频 + 出图),装上就能在字字里选型号、填描述、直接出片。

查看插件说明 / 下载插件包 →

插件和接口是同一套东西:插件用的是本文档这些 /v1/* 接口, 参数完全一致。所以插件里遇到问题,把「运行日志」里的请求体拿出来, 对照本文档就能判断是谁的问题。

插件怎么装、怎么填 Key、每个选项什么意思 —— 写在飞书教程里 (「在「字字动画」里用插件」这一章),比这里详细: 打开飞书教程。

附录 A:完整 Python 示例(提交 → 轮询 → 取片)

照抄就能跑。注意最后一步用的是响应里给的 artifact.url, 并且落盘后要验完整性(字节数 / ftyp / moov)—— 只判断"写了多少字节"会把半截片子当成功,播放器却打不开。

import os, time, requests

BASE = "https://xyjingyuapi.com"          # 不含 /v1
API = BASE + "/v1"
H = {"Authorization": "Bearer sk-你的密钥"}

r = requests.post(API + "/videos", headers=H, json={
    "model": "nh-2.5-t-720p",
    "prompt": "镜头缓慢推近,人物微微转头看向镜头",
    "size": "720x1280",          # ★ 必填:竖屏 9:16。不传会 400(size_required)
    "aspect_ratio": "9:16",      # ★ 建议:显式给比例,服务端优先用它(和 size 说的是同一件事)
    "images": ["https://你的图床/ref.jpg"],   # ★ 必带;首帧用 input_reference
})
r.raise_for_status()
vid = r.json()["id"]

while True:
    s = requests.get(API + "/videos/" + vid, headers=H).json()
    print(s["status"], s.get("progress"))
    if s["status"] in ("completed", "failed"):
        break
    time.sleep(15)               # 15~30 秒一次就够,别更密

if s["status"] != "completed":
    print("失败原因:", s["error"]["message"], "(钱已退回)")
    raise SystemExit(1)

# ★ 用响应里给的地址(相对路径),不要自己拼、也不要去找任何"直链"
url = BASE + s["artifact"]["url"]
path = "片子.mp4"
for _try in range(3):
    have = os.path.getsize(path) if os.path.exists(path) else 0
    hdrs = dict(H)
    if have:
        hdrs["Range"] = "bytes=%d-" % have            # 断点续传
    with requests.get(url, headers=hdrs, stream=True, timeout=180) as resp:
        if resp.status_code == 416:                   # 已经下全了
            break
        resp.raise_for_status()
        # 200 = 整份重给 ⇒ 必须从头覆盖;206 = 续传 ⇒ 接着写
        append = (resp.status_code == 206 and have > 0)
        total = resp.headers.get("Content-Length")
        with open(path, "ab" if append else "wb") as f:
            for chunk in resp.iter_content(256 * 1024):
                if chunk:
                    f.write(chunk)
    size = os.path.getsize(path)
    ok_size = (not total) or size == (have if append else 0) + int(total)
    blob = open(path, "rb").read()
    if ok_size and b"ftyp" in blob[:32] and b"moov" in blob:
        break                                          # 三条都过才算下好
    print("这次没下完(%d 字节),接着下…" % size)
else:
    raise RuntimeError("下载不完整 —— 别重新生成(会再扣一次),到控制台「日志」里手动下载")

print("已保存,字节数 =", os.path.getsize(path))

需要"下成片"这个单独函数的话,把上面 for _try in range(3): 那一段抽出来就是 —— 不要另写一份,两份必然漂移。