cocodot
← 返回教程
国内卡付不了海外 AI?cocodot 一张卡 + 一个 Key 搞定
视频生成 API更新于 2026-11

视频生成 API 怎么用 Python 轮询?间隔、超时、一直 PENDING 与不重复扣费(2026)

视频生成接口是异步的:提交拿任务 ID,再轮询查询任务状态。本文按 cocodot 视频接口的实际行为讲轮询间隔、总截止时间、提交超时后怎么避免一条视频付两次钱、没有回调和取消时怎么设计脚本,并给出一个可断点续查的 Python 轮询器。

一句话结论:用 Python 调视频生成 API,稳妥的写法是:提交一次 → 立刻把任务 ID 记到本地 → 每 10–15 秒查一次 → 给自己设总截止时间 → 成功后马上下载转存。cocodot 的视频接口是异步的:POST https://cocodot.co/api/ai/video/generations 返回任务 ID,GET https://cocodot.co/api/ai/video/generations/{id} 查询任务状态,状态只有 PENDING、SUCCEEDED、FAILED 三种。按当前接口实现,同一个任务 10 秒内重复查询不会去取新状态,轮询再密也只是多拿几次 PENDING;请求里带回调地址会被忽略,不会回调,只能轮询;也没有取消接口,脚本停了任务照样在生成,出片后照常结算。提交时如果你这边超时,先用 GET https://cocodot.co/api/ai/video/generations 查最近的任务列表,确认任务有没有建起来,再决定要不要重投,否则可能一条视频付两次钱。同一账户同时在生成中的任务最多 3 条,批量出片要在自己的代码里排队。

1. 先把接口的形状记清楚

cocodot 的视频生成接口分三件:提交 POST https://cocodot.co/api/ai/video/generations,查单个任务 GET https://cocodot.co/api/ai/video/generations/{id},查最近的任务列表 GET https://cocodot.co/api/ai/video/generations。三个都用 Authorization: Bearer cocodot-… 的 API Key,也接受登录 token。提交成功返回任务的 id、status、model、createdAt,此时 status 是 PENDING。查单个任务时,PENDING 表示还在生成;SUCCEEDED 时带 videoUrl;FAILED 时带 error,是一句中文原因。任务列表返回你账户最近 50 条任务,新的在前,每条有 id、model、status、提示词前 300 字(用 content 传文本提示词时才有)、resolution、videoUrl、createdAt 和这条实际收了多少钱的 costUsd。可用的型号和每个型号能选的分辨率、时长、档位,以 GET https://cocodot.co/api/ai/video/models 返回为准,在你的代码里先按它校验参数,不合法的请求根本不要发出去。调用前须完成实名 L1,视频不能使用 $0.5 体验额度。三家请求体字段各不一样,写法和每类报错怎么处理见 /hub/video-api-error-codes-fix,本文只讲轮询这一段怎么写才稳。

2. 轮询间隔:10 秒内重复查拿不到新东西

很多人写轮询的第一反应是「查得越勤,拿到视频越快」。在 cocodot 上不是这样:按当前接口实现,同一个任务距离上一次实际查询不到 10 秒时,接口不会去取新状态,直接返回 PENDING。所以 1 秒一次的轮询和 10 秒一次的轮询,拿到 SUCCEEDED 的时间几乎一样,前者只是白白多发了很多请求,还更容易被你自己的网络抖动打断。建议:提交后先等 15 秒再查第一次,之后固定每 10–15 秒查一次;如果你一次跑很多条,可以把间隔放宽到 20–30 秒,对出片时间影响很小。另外,后台也会每隔几分钟自动查一遍所有还在生成中的任务,所以就算你的脚本暂时没在查,任务的状态也会继续往前走。生成要多久取决于型号、分辨率和时长,我们不给固定数字,自己跑几条记下实际用时,再据此设截止时间。

3. 一直 PENDING:先分清「还在生成」和「暂时查不到」

PENDING 不等于「一定在跑」。按当前实现,有几种情况都会让你看到 PENDING:任务确实还在生成;离上一次实际查询不到 10 秒;服务端这一次去查结果时出了临时问题,接口不报错,只返回 PENDING;提交时结果未知,任务还在等确认。所以轮询脚本不能只靠「等到不是 PENDING 为止」,必须自己设一个总截止时间,按你的业务能等多久来定,比如 30 分钟或 1 小时。到点还是 PENDING 时,不要重新提交 —— 重投等于再建一条新任务、再预扣一次钱。正确做法是把任务 ID 记下来,脚本退出,过一段时间再用单任务查询或任务列表补查。服务端也有兜底:提交结果未知、2 小时内没能确认受理的任务,会自动转成 FAILED 并把预扣全额退回;已经受理但 72 小时还没出结果的,同样自动转 FAILED、全额退回。两种情况 error 都是「视频生成失败,本次未扣费,请稍后重试;如多次失败,请检查参数或内容。」看到这句再决定要不要重投。

4. 提交超时:先查列表,别急着重投

这是轮询脚本里最容易多花钱的地方。cocodot 收到提交后,会先建好任务、按保守预估把钱预扣下来,再去提交生成;同一账户的提交是一条一条处理的,单次提交可能要等比较久。如果你在 requests.post 里把 timeout 设成 10 秒,很可能你这边已经报超时,服务端那条任务其实已经建好、钱也预扣了。这时候脚本自动重试,就是第二条任务、第二次扣费。建议三件事:第一,提交的 timeout 给足,120 秒左右;第二,提交超时或断线时不自动重试,而是调 GET https://cocodot.co/api/ai/video/generations 看最近的任务,按 model、createdAt 和提示词前缀找有没有刚建起来的那一条,找到了就接着轮询它;第三,多线程同时提交并不会更快,因为同一账户的提交本来就是排队处理的,反而让超时更难判断。还有一种情况:提交时如果生成服务那边的结果未知,接口仍然会返回任务 ID 和 PENDING,这条任务照常轮询即可,2 小时内没能确认的会按上一节说的自动退回。

5. 没有回调、没有取消:脚本停了,钱照样结算

有的视频平台支持在提交时填一个回调地址,出片后主动通知你。cocodot 的视频接口目前不做回调:请求体里带 callback_url、webhook 之类的字段不会报错,但会被直接忽略,不会有任何通知,所以只能轮询。也没有取消任务的接口。这一点对写脚本的人很重要:你按 Ctrl+C 停掉脚本、关掉服务器、或者轮询超时退出,都只是你这边不再查了,任务本身还在生成,出片后后台会照常结算,按实际用量多退少补,视频会出现在任务列表里,costUsd 就是这条实际收的钱。反过来说,如果你发现参数填错了,停脚本不能止损,只能等这条结束。所以批量跑之前,先用一两条低规格的请求把参数、提示词和下载流程走通,再放大规模。任务失败的不扣费,预扣全额退回。

6. 批量出片:同时最多 3 条,在自己代码里排队

同一账户同时在生成中的任务最多 3 条,第 4 条提交会直接返回 400「同时最多 3 条视频在生成,请等已提交的完成后再提交」,不建任务、不扣费。另外每次提交都会先检查余额:预扣是按这条视频的预估金额算的,正在生成的任务已经各自预扣过,余额不够时会返回「钱包余额不足」并附上这条的预估金额。批量时的写法是:把待生成的请求放进一个队列,同时最多保持 3 条在生成;每提交成功一条,立刻把任务 ID、型号、提交时间追加写进本地文件;某条结束(成功或失败)再从队列里取下一条。不要用「提交失败就 sleep 一下再提交」来硬顶并发上限,那样一旦遇到上一节说的超时,很难分清哪条真的没建起来。本地记录文件就是你的账本:脚本重启时先读它,再和任务列表对一遍,只补查、不重投。

7. 拿到 SUCCEEDED 之后:下载、转存、对账

SUCCEEDED 的返回里有 videoUrl,它指向生成结果的下载地址,不在你自己的存储里,能保留多久我们不做承诺,拿到后应尽快下载到你自己的存储里。下载建议用流式写文件,不要一次读进内存;下载失败时先重新 GET 一次任务再下:按当前实现,海螺型号的成片是带签名的临时链接,对已成功的海螺任务再查一次,接口会在需要时重新获取链接;其它型号再查一次返回的是同一条链接,如果已经打不开,就记下任务 ID 联系客服。对账方面,提交时预扣的是保守预估金额,出片后按实际用量结算、多退少补;每条最终收了多少钱,以任务列表里的 costUsd 为准,不要拿提交时报错里的预估金额当实际成本。建议把任务 ID、型号、规格、costUsd、本地文件路径写进同一条记录,以后算单条成本或者找客服核对都用得上。各型号的计费方式和价格见 /hub/ai-video-api-price-compare 和价格页。

8. 完整脚本:可断点续查的 Python 轮询器

下面这个脚本把前面几条都落实了:提交超时给足、成功后立刻记本地文件;查询间隔 15 秒、有总截止时间;网络抖动时接着查同一个任务,绝不重新提交;下载前重新取一次链接;脚本重启或提交超时后用 resume() 和任务列表对账,只查不重投。它只依赖 requests,把 Bearer 后面换成你自己的 cocodot API Key 即可。用法:提交拿到任务 ID 后调用 wait(),成功再调用 download();出了任何意外,先跑 resume() 看清楚服务端的状态,再决定下一步。提交被拒(400 / 401 / 403 / 429 / 503)和任务 FAILED 时具体该改什么、哪些值得重试,按 /hub/video-api-error-codes-fix 的对照表处理,本脚本示范记录已知任务 ID 和避免自动重投,不能保证恢复返回 ID 之前中断的请求。任务列表只显示最近 50 条,看不到匹配项也不能证明未创建;无法确认时保留未知状态并联系客服。

可断点续查的视频任务轮询器(型号与参数以 /api/ai/video/models 为准)
import json, time, pathlib, requests

API = "https://cocodot.co/api/ai/video/generations"
H = {"Authorization": "Bearer cocodot-..."}
LOG = pathlib.Path("video_tasks.jsonl")  # 每提交成功一条就追加一行,脚本断了也能续查

def submit(body):
    # 同一账户的提交逐条处理,单次可能要等较久:超时给足,超时后不要自动重投
    r = requests.post(API, json=body, headers=H, timeout=120)
    if not r.ok:
        raise RuntimeError(f"{r.status_code} {r.text}")  # 各类报错的处理见 /hub/video-api-error-codes-fix
    tid = r.json()["id"]
    with LOG.open("a", encoding="utf-8") as f:
        f.write(json.dumps({"id": tid, "model": body["model"], "at": time.time()}, ensure_ascii=False) + "\n")
    return tid

def wait(tid, interval=15, deadline_s=3600):
    end = time.time() + deadline_s
    while time.time() < end:
        time.sleep(interval)  # 同一任务 10 秒内重复查不会拿到新状态
        try:
            r = requests.get(f"{API}/{tid}", headers=H, timeout=90)
            r.raise_for_status()
            t = r.json()
        except requests.RequestException:
            continue  # 网络抖动:接着查同一个任务,绝不重新提交
        if t["status"] == "SUCCEEDED":
            return t
        if t["status"] == "FAILED":
            raise RuntimeError(f"{tid} FAILED: {t.get('error')}")
    raise TimeoutError(f"{tid} 到截止时间仍是 PENDING:稍后用 resume() 补查,不要重投")

def download(tid, path):
    for _ in range(2):
        response = requests.get(f"{API}/{tid}", headers=H, timeout=90)
        response.raise_for_status()
        t = response.json()  # 每次下载前重新取链接
        r = requests.get(t["videoUrl"], stream=True, timeout=300)
        if r.ok:
            with open(path, "wb") as f:
                for chunk in r.iter_content(1 << 20):
                    f.write(chunk)
            return path
        time.sleep(5)
    raise RuntimeError(f"{tid} 下载失败,记下任务 ID 稍后再试")

def resume():
    """脚本重启或提交超时后:先对账,只查不重投。"""
    response = requests.get(API, headers=H, timeout=60)
    response.raise_for_status()
    recent = response.json()  # 最近 50 条,并非完整历史
    for x in recent:
        if x["status"] == "PENDING":
            print("仍在生成:", x["id"], x["model"], x["createdAt"], (x.get("prompt") or "")[:40])
    known = {json.loads(l)["id"] for l in LOG.read_text(encoding="utf-8").splitlines()} if LOG.exists() else set()
    for x in recent:
        if x["id"] not in known:
            print("本地没记、服务端有:", x["id"], x["status"], x["createdAt"])

轮询脚本要处理的情况(按 cocodot 视频接口当前行为整理)

情况接口实际行为代码里怎么写
10 秒内重复查同一任务不去取新状态,直接返回 PENDING间隔设 10–15 秒,再密没有用
查询过程中服务端暂时查不到结果返回 PENDING,不报错自己设总截止时间,到点停下改为补查
POST 在你这边超时或断线任务可能已经建好并预扣先查任务列表;没看到匹配项也不能证明未创建,保留未知状态并联系客服确认后再决定
请求体里带 callback / webhook 字段被忽略,不会回调只用轮询
想中途取消没有取消接口,停止轮询不会停止生成提交前把参数核对好
已有 3 条在生成又提交第 4 条返回 400,不建任务用队列把同时生成数控制在 3 以内
提交结果未知,2 小时内没确认受理自动转 FAILED,预扣全额退回按 error 原文决定要不要重投
已受理但 72 小时没出结果自动转 FAILED,预扣全额退回同上
海螺成片链接过期对已成功的海螺任务再 GET 一次,返回重新获取的链接下载前先 GET 一次拿最新链接

常见问题

视频生成任务一直是 PENDING,要重新提交吗?

不要重投。PENDING 可能是还在生成,也可能是这一次暂时查不到结果。保持 10–15 秒一次的间隔继续查同一个任务 ID;超过你设的截止时间就先退出,稍后再查。服务端对 2 小时内没能确认受理的、以及受理后 72 小时没结果的任务,会自动转 FAILED 并全额退回预扣。

轮询间隔设多少合适?查得越勤越快吗?

不会更快。按当前实现,同一个任务 10 秒内重复查询不会取新状态,建议提交后等 15 秒再查,之后每 10–15 秒一次,批量时可以放宽到 20–30 秒。

Python 提交时超时了,会不会重复扣费?

可能会,如果你自动重试的话。超时时任务可能已经建好并预扣,先调 GET /api/ai/video/generations 看最近的任务,找到就继续轮询那一条;列表没看到匹配项也不能证明没创建,先保留未知状态并联系客服确认。提交的 timeout 建议给到 120 秒左右。

cocodot 的视频 API 支持 webhook 回调吗?

目前不支持。请求里带 callback 或 webhook 字段会被忽略,不会回调,只能轮询。

停止轮询或者关掉脚本,能取消视频任务吗?

不能。没有取消接口,停止轮询只是你不再查,任务会继续生成,出片后照常结算。参数要在提交前核对好。

成片链接打不开了怎么办?

先重新 GET 一次任务:海螺型号会在需要时重新获取链接;其它型号返回的是同一条链接,打不开就记下任务 ID 联系客服。拿到链接后尽快下载转存到自己的存储。

关于 cocodot

cocodot 是面向中国大陆开发者与出海团队的支付与 AI 接入服务:由持牌机构发行的美国卡段虚拟卡(用于在海外网站完成订阅与广告扣费),以及 OpenAI 兼容的 AI API 中转(在中国大陆直连调用 Claude、GPT、Gemini)。两者共用同一个钱包,支持支付宝 / 微信支付(人民币)、USDT / USDC 充值、以美元记账。卡费率:开卡 $9.9、充值到卡 3%、每张活跃卡每月 $1;消费:单笔 <$20 收 $0.60 结算费;发卡方按笔收费时另收相应费用。

服务范围、价格与能力边界 →