OpenAPI 接入:开放应用、签名与接口清单
创建开放应用与接口开关、请求头与签名算法、Python 示例、视频/演员/标签/专辑/发行商/Telegram Bot/采集接口的地址与用法。
OpenAPI 让第三方系统(采集工具、重写脚本、Telegram 机器人、内容同步程序)通过签名认证读取或写入站内数据。接口由**前台服务(默认 6166 / 你的前台域名)**提供,路径前缀为 /openApi/v1。
与后台接口的区别
后台管理接口(6188,全程 AES 加密)只给后台页面使用,不要拿它做对接。OpenAPI 使用 X-OpenAPI-* 请求头 + query 签名,不依赖前台登录态,也不需要前台加密协议。
订阅功能
「开放接口扩展」属于订阅能力,未获得授权时部分接口或配置可能不可用,详见订阅与高级功能一览。
接入准备:后台配置
后台左侧菜单「开放接口」下有两个页面:
| 页面 | 路由 | 作用 |
|---|---|---|
| 接口配置 | /openApi/interfaceConfig |
统一控制公共采集、视频、演员、专辑、发行商、标签等开放 API 是否启用,以及每类接口开放哪些操作 |
| 应用管理 | /openApi/apps |
创建开放应用,获得 App ID 与 Secret,配置接口范围、签名算法、IP 白名单、限流等 |


接口配置:每个模块(视频、演员、标签、专辑、发行商)有「增 / 删 / 改 / 查」四个操作开关;另有「公共采集接口」开关。接口未启用时调用会返回 403。
应用管理(开放应用)字段:
| 字段 | 说明 |
|---|---|
| 账号名称 / 账号状态 | 启用或禁用;禁用后该应用所有请求认证失败 |
| App ID | 请求头 X-OpenAPI-App-ID 使用 |
| Secret / Secret 指纹 | Secret 明文只在创建或「重置应用密钥」时一次性显示,请立即保存;列表只显示指纹 |
| 接口范围 | 视频/演员/专辑/标签/厂商的 读取、新增、编辑(/关联)、删除,以及 Bot 机器人读取、Bot 机器人标记 |
| 签名算法 | 可勾选 md5、sha256、HMAC-MD5、HMAC-SHA256;请求的 sign_method 必须是已启用的之一 |
| IP 白名单 | 开启后只有名单内出口 IP 可调用 |
| 限流 | 每分钟请求上限,超出返回 429 |
| 时间戳偏差 | 允许的客户端时间偏差秒数;未配置时默认 300 秒 |
| 输出详细错误 | 开启后认证失败会返回更具体原因(如「签名无效」),调试时开启,上线后建议关闭 |
一次成功调用要同时满足:应用已启用、对应接口模块与操作已在「接口配置」开启、应用「接口范围」包含该操作、IP/限流/时间戳通过、签名正确。
建议用最小权限
为每个对接方单独创建应用,只勾选它需要的范围;不要把 Secret 写进前端代码或公开仓库;泄露后立即「重置应用密钥」。
认证与签名
请求头与 query 参数
| 位置 | 名称 | 必填 | 说明 |
|---|---|---|---|
| 请求头 | X-OpenAPI-App-ID |
是 | 开放应用 ID(不参与签名) |
| 请求头 | X-OpenAPI-Signature |
是 | 签名结果,hex,校验时不区分大小写(不参与签名) |
| query | sign_method |
是 | md5 / sha256 / hmac-md5 / hmac-sha256 |
| query | timestamp |
是 | 秒级时间戳,与服务器时间偏差不能超过应用配置的容忍秒数 |
| query | body_hash |
POST 必填 | 原始 JSON body 的 sha256 小写 hex;GET 不需要 |
签名算法
- 取 URL 中全部 query 参数(排除名为
sign的参数),按参数名排序并 URL 编码,得到canonicalQuery(即标准的 URL 编码,参数名排序后用 &、= 拼接)。业务参数(GET)和sign_method、timestamp、body_hash都在其中;POST 的业务参数在 JSON body 里,通过body_hash间接参与签名; secretHash = sha256(明文 secret)的小写 hex;- 按
sign_method计算:
sign_method |
签名 |
|---|---|
md5 |
hex(md5(canonicalQuery + secretHash)) |
sha256 |
hex(sha256(canonicalQuery + secretHash)) |
hmac-md5 |
hex(hmac-md5(key=secretHash, msg=canonicalQuery)) |
hmac-sha256 |
hex(hmac-sha256(key=secretHash, msg=canonicalQuery)) |
Python 示例
下面的示例已与服务端的签名函数对拍验证(同样的 query、secret 得到相同的签名值):
import hashlib, hmac, json, time, urllib.parse, urllib.request
BASE_URL = "https://www.example.com" # 你的前台域名
APP_ID = "fc_app_xxx" # 开放应用的 App ID
SECRET = "sk_live_xxx" # 明文 secret
SIGN_METHOD = "hmac-sha256" # 必须是该应用已启用的算法
def sign(query: dict, ts=None):
q = dict(query)
q["sign_method"] = SIGN_METHOD
q["timestamp"] = str(ts or int(time.time()))
canonical = urllib.parse.urlencode(sorted(q.items())) # canonicalQuery
secret_hash = hashlib.sha256(SECRET.encode()).hexdigest()
sig = hmac.new(secret_hash.encode(), canonical.encode(), hashlib.sha256).hexdigest()
return canonical, sig
def get(path, params):
canonical, sig = sign(params)
req = urllib.request.Request(f"{BASE_URL}{path}?{canonical}",
headers={"X-OpenAPI-App-ID": APP_ID, "X-OpenAPI-Signature": sig})
return json.load(urllib.request.urlopen(req))
def post(path, body: dict):
raw = json.dumps(body, ensure_ascii=False, separators=(",", ":")).encode()
canonical, sig = sign({"body_hash": hashlib.sha256(raw).hexdigest()})
req = urllib.request.Request(f"{BASE_URL}{path}?{canonical}", data=raw, method="POST",
headers={"X-OpenAPI-App-ID": APP_ID, "X-OpenAPI-Signature": sig,
"Content-Type": "application/json"})
return json.load(urllib.request.urlopen(req))
print(get("/openApi/v1/videos", {"page": 1, "page_size": 20}))对拍用例:page=1&page_size=20&sign_method=hmac-sha256×tamp=1779184800,secret 为 sk_live_xxx 时签名为 908d48418022603f3c300f76a3eec2015f260e5f50bfb3c90ee7a76583f6c323。POST 的 body_hash 必须按实际发送的原始字节计算,所以示例里先序列化为 raw,再用同一份 raw 发送。
响应与状态码
成功:{"code":1,"message":"获取成功","data":{...}};失败:{"code":0,"message":"..."}。
| HTTP 状态码 | 场景 |
|---|---|
400 |
参数或 JSON body 无效 |
401 |
认证失败:签名算法未开启、签名无效、body_hash 无效、时间戳无效 |
403 |
接口未启用、缺少接口范围、IP 白名单拒绝、游标任务不可用 |
404 |
资源不存在、游标没有下一条 |
409 |
资源重复或游标已推进 |
429 |
应用每分钟限流达到上限 |
500 |
系统处理失败 |
接口清单
所有路径都挂在前台域名下,例如 https://www.example.com/openApi/v1/videos。
视频
| 接口 | 方法 | 接口范围 |
|---|---|---|
/openApi/v1/videos |
GET | 视频读取 |
/openApi/v1/videos/detail |
GET | 视频读取 |
/openApi/v1/videos/cursor-detail |
GET | 视频读取 |
/openApi/v1/videos/create |
POST | 视频新增 |
/openApi/v1/videos/update |
POST | 视频编辑 |
/openApi/v1/videos/delete |
GET | 视频删除 |
视频列表参数:page(默认 1)、page_size(默认 20,最大 100)、ids(逗号分隔本地 ID)、keyword、category_id、sort_by(id/created_at/updated_at/views_count/like_count/source_updated_at 等)、sort_order(asc/desc)、lang(默认 zh_cn)。列表不返回播放地址和分集详情。
视频详情:id 只能传一个本地视频 ID。
游标详情(适合批量改写/同步任务):传 cursor_key(仅字母、数字、下划线,长度 1–16;不存在会自动创建任务),返回 id 大于游标位置的第一条前台可见视频,只读取不推进游标;之后调用「修改视频」时带上同一个 cursor_key,修改成功才推进游标。不允许同时传 id/ids。
新增视频(POST,query 需 sign_method、timestamp、body_hash)必填字段:source_id(已存在的采集源)、source_category_id(属于该 source_id)、source_video_id、titles({"语言标识":"标题"},至少一个非空标题)。source_id + source_video_id 已存在(含已删除)返回 409。可选:封面/预览地址、area/lang/year、统计数、access_mode、price(单位:分)、episodes、tags、actors(按名称查找或创建)等。示例 body:
{"source_id":1,"source_category_id":8,"source_video_id":9001,"titles":{"zh_cn":"示例视频"}}修改视频:id 为本地 ID,只更新传入的 titles/descriptions 等字段,不修改演员、分类、标签、专辑、厂商和分集;可选 cursor_key 推进游标。删除视频是标记删除,只传一个 id,之后普通读取接口不再返回。
演员、标签、专辑、发行商
四类资源的接口形态一致(以演员为例,actors 换成 tags / albums / issuers 即可):
| 接口 | 方法 | 说明 |
|---|---|---|
/openApi/v1/actors |
GET | 分页列表,lang 控制名称/别名/简介语言 |
/openApi/v1/actors/detail |
GET | 详情,id 单个 |
/openApi/v1/actors/cursor-detail |
GET | 游标详情,同视频规则 |
/openApi/v1/actors/create |
POST | 新增(names 至少一个语言的名称) |
/openApi/v1/actors/update |
POST | 修改,可带 cursor_key |
/openApi/v1/actors/link-video |
POST | 关联视频:actor_id + video_id,已关联时 changed=false,重复调用也返回成功 |
/openApi/v1/actors/unlink-video |
POST | 取消关联,未关联时 changed=false |
/openApi/v1/actors/delete |
GET | 删除,只传一个 id,会移除相关视频关联 |
标签的 count 不允许由客户端直接写入。接口范围名称:演员/专辑/标签的「读取、新增、编辑/关联、删除」,发行商对应「厂商读取/新增/编辑/关联/删除」。
Telegram 机器人
| 接口 | 方法 | 接口范围 | 说明 |
|---|---|---|---|
/openApi/v1/telegram-bot |
GET | Bot 机器人读取 | 查询待推送视频;identifier(1–16 字符)必填,会排除该 identifier 已标记推送的视频;支持分页、分类、搜索、入库/源更新时间区间、排序 |
/openApi/v1/telegram-bot/source-categories |
GET | Bot 机器人读取 | 源分类列表,供筛选 |
/openApi/v1/telegram-bot/mark |
POST | Bot 机器人标记 | body:identifier 与 video_ids(正整数列表,最多 100 条);幂等 |
identifier 只影响当前机器人或频道,不同频道用不同 identifier 即可各自独立记录推送进度。
公共采集接口(苹果 CMS 兼容)
GET|POST /openApi/v1/collect,不需要签名,只受「接口配置 → 公共采集接口」开关控制(关闭时返回 HTTP 403,{"code":0,"msg":"接口未启用"})。仅输出 JSON(不支持 XML),输出的是原始采集数据中的图片和播放地址,不按会员/付费权限过滤,也不写入访问统计。
| 参数 | 说明 |
|---|---|
ac |
为空或 list 返回列表(含 class 分类);detail 返回详情列表 |
t |
本地分类 ID |
ids |
本地视频 ID,逗号分隔 |
pg |
页码,从 1 开始 |
limit / pagesize |
每页数量,最大 100;同时传时优先 limit |
wd |
按默认语言标题搜索 |
对外使用的是本地分类:源分类需要先在采集管理里绑定到本地分类,未绑定的源分类下的视频不会出现在 list/detail 中。
联调检查清单
- 「接口配置」中对应模块与操作已开启;
- 开放应用已启用,「接口范围」勾选了对应项,签名算法与请求的
sign_method一致; - 调用方服务器时间准确(偏差在容忍秒数内,默认 300);
- 出口 IP 在白名单内(若开启);
- 开启「输出详细错误」联调,返回
401时看具体原因,完成后关闭; - POST 的
body_hash用实际发送的原始字节计算。