API 与集成
每个房间都有 HTTP API。您可以通过脚本、演出控制系统或任何能发起 Web 请求的工具来启动和停止计时器、显示消息、增加时间以及读取节目流程表。计时器开始或结束时,webhook 会通知您的系统。


快速开始
创建 API 密钥
打开 API 密钥,点击 创建密钥。请立即复制:它只显示一次。参见 团队与 API 密钥。
找到房间 id
它是控制室地址中 /timer/r/ 之后的部分,例如 https://cliqer.io/timer/r/<room>/control。
发起调用
每次请求都要附带密钥。ping 用于检查房间是否存在。
API 与控制室操作的是同一个房间:您的工具发出的调用会同时显示在所有屏幕上。
请求
每个调用的地址都是 https://cliqer.io/api/timer/v1/<room>/<action>。GET、POST、PUT 和 PATCH 均可使用。参数放在查询字符串中,或者在 POST、PUT 和 PATCH 请求中放在 JSON 正文里;两者都有时以正文为准。操作名称中使用短横线也可以,因此 add-time 等同于 add_time。/api/timer/v0/ 接受相同的调用。
按以下任一方式发送密钥,系统按此顺序检查:
| 位置 | 示例 |
|---|---|
Authorization 请求头 | Authorization: Bearer <key> |
x-api-key 请求头 | x-api-key: <key> |
api_key 查询参数 | ?api_key=<key>。请尽量避免使用:地址会被记录到日志中。 |
curl -X POST https://cliqer.io/api/timer/v1/<room>/add_time \
-H "Authorization: Bearer $CLIQER_KEY" \
-H "content-type: application/json" \
-d '{"timer_id": "<timer>", "amount": "2m"}'
const res = await fetch('https://cliqer.io/api/timer/v1/<room>/add_time', {
method: 'POST',
headers: { 'authorization': `Bearer ${process.env.CLIQER_KEY}`, 'content-type': 'application/json' },
body: JSON.stringify({ timer_id: '<timer>', amount: '2m' }),
})
const { ok, message, data } = await res.json()
import os, requests
r = requests.post(
"https://cliqer.io/api/timer/v1/<room>/add_time",
headers={"Authorization": f"Bearer {os.environ['CLIQER_KEY']}"},
json={"timer_id": "<timer>", "amount": "2m"},
)
print(r.json())
密钥与权限
您的账户 API 密钥可以对您拥有的房间执行所有操作。房间也可以拥有自己的密钥,每个密钥具有以下三种权限中的部分权限:
| 权限 | 允许 |
|---|---|
| 读取 | get_ 类操作和 export。 |
| 演出控制 | 播放控制、时间、黑屏、「直播中」标志和消息。 |
| 编辑 | 删除、导入、原始 intent 和 webhook。 |
如果调用所需的权限是该密钥不具备的,将收到 401。房间密钥的密钥值仅在创建时显示一次。要使用 API,您的套餐必须包含 API,参见 套餐与限制。
操作
timer_id 按 id 选择计时器;index 按位置选择,从 1 开始计数。两者同时发送时,以 timer_id 为准。两者都不填时,操作作用于当前计时器。
| 操作 | 返回 |
|---|---|
get_room | 标题、日期、时区和设置。 |
get_status | 当前正在运行的内容。 |
get_timers | 节目流程表。 |
get_messages | 消息。 |
get_questions | 观众提问。 |
get_connections | 已连接的设备。 |
get_logs | 房间日志。limit、offset。 |
export | 以 cliqer-timer-<room>.json 文件下载整个房间。 |
| 操作 | 参数 | 作用 |
|---|---|---|
start、start_or_stop | timer_id 或 index | 启动,或切换启停。 |
stop | 停止正在运行的计时器。 | |
start_fresh | timer_id 或 index | 从完整时长开始。 |
select | timer_id 或 index(必须提供其一) | 设为当前计时器但不启动。 |
reset | timer_id 或 index、autostart、from_memory | 恢复到完整时长。 |
next、previous | autostart、from_memory | 在节目流程表中前后移动。 |
add_time、subtract_time | timer_id、amount | 更改计时器的时长。 |
jump | amount | 让正在运行的计时器跳过相应时长。 |
set_remaining | amount | 设置剩余时间。 |
flash | count、message | 让屏幕闪烁。 |
stop_flash | 停止闪烁。 | |
blackout | on | 开启或关闭黑屏。 |
blackout_on、blackout_off、toggle_blackout | 作用相同,无需参数。 | |
focus | on | 突出显示消息。 |
on_air | on | 「直播中」标志。 |
show_message | message_id、focus | 显示一条消息。 |
toggle_message | message_id | 显示该消息,如已显示则隐藏。 |
hide_message | 隐藏消息。 |
| 操作 | 参数 | 作用 |
|---|---|---|
delete_timer | timer_id | 删除计时器。 |
delete_message | message_id | 删除消息。 |
delete_question | question_id | 删除提问。 |
import_csv | csv、replace、date_line、columns、header_row、rows | 导入行数据,方式同 从 Stagetimer 导入。 |
intent | {"intent": {...}} | 以 JSON 形式执行控制室能做的任何更改。 |
webhook | url | 设置或清除 webhook。见下文。 |
| 操作 | 参数 | 作用 |
|---|---|---|
ping | 房间存在时返回 pong。 | |
submit_question | text(最多 1000 个字符)、name(最多 100 个) | 提交观众提问。 |
vote_question | question_id | 为某个提问投票。 |
时长 可写作 30s、5m、1h、250ms,或不带单位的秒数。可用 seconds 代替 amount,加负号则向回调整。开关 类参数(如 on、autostart 和 replace)将 0、false、off 和 no 视为关闭,其他任何值都视为开启。blackout 不带 on 时切换黑屏状态。
响应
所有响应均为 JSON:成功时为 {"ok": true, "message": "<action>", "data": ...},失败时为 {"ok": false, "message": "...", "code": "..."}。
| 状态码 | 消息 | 原因 |
|---|---|---|
| 400 | Either timer_id OR index are required | select 未指定计时器。 |
| 400 | amount is required, like 30s, 5m or 1h | 缺少时长或无法解析。 |
| 400 | Refused: invalid | 房间无法应用该操作。 |
| 401 | Access Denied: Valid API key required | 没有密钥、密钥错误或缺少权限。 |
| 403 | The API is not in this plan | 该房间的套餐不含 API。 |
| 403 | Refused: forbidden、Refused: readOnly、Refused: limitReached | 不允许、房间为只读,或达到套餐限制。 |
| 404 | Room not found、Unknown action <name>、Timer not found | 请检查房间 id、操作名称或计时器 id。 |
| 409 | Refused: staleEpoch | 调用期间房间状态已发生变化。请重新发送。 |
| 429 | Too many requests. Please try again later. | 速率限制。 |
| 503 | Refused: authorityOffline | 房间在回收站中。请先恢复。 |
速率限制: 每个密钥每分钟 100 次调用;不带密钥的调用按来源地址计数。每个响应都带有 RateLimit-Limit、RateLimit-Remaining 和 RateLimit-Reset(距离下一分钟开始的秒数)。
Webhook
设置地址
使用 https 的 url 调用 webhook。响应中包含以 whsec_ 开头的 secret。请妥善保存:它只显示一次。
接收事件
房间中发生事件时,Cliqer Timer 会向该地址发送 POST 请求。
校验签名
在信任每个请求之前,先进行验证。
清除
调用 webhook 时不带 url。地址及其签名密钥都会被删除。
| 事件 | 触发时机 |
|---|---|
timerStarted | 计时器启动。 |
timerEnded | 计时器归零。 |
wrapUpYellow | 计时器到达黄色收尾提示点。 |
wrapUpRed | 计时器到达红色收尾提示点。 |
messageShown | 显示一条消息。 |
正文为 {"event", "roomId", "timestamp", "payload"}。x-cliqer-timestamp 请求头包含以秒为单位的 Unix 时间,x-cliqer-signature 包含 sha256= 及以您的签名密钥对 <timestamp>.<body> 计算出的十六进制 HMAC-SHA256。
# Recompute the signature of a saved body.
printf '%s.%s' "$TIMESTAMP" "$(cat body.json)" \
| openssl dgst -sha256 -hmac "$WHSEC" -hex
import { createHmac, timingSafeEqual } from 'node:crypto'
export function verify(rawBody: string, timestamp: string, signature: string, secret: string) {
const want = `sha256=${createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')}`
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300
return fresh && want.length === signature.length && timingSafeEqual(Buffer.from(want), Buffer.from(signature))
}
import hashlib, hmac, time
def verify(raw_body: bytes, timestamp: str, signature: str, secret: str) -> bool:
mac = hmac.new(secret.encode(), timestamp.encode() + b"." + raw_body, hashlib.sha256)
fresh = abs(time.time() - int(timestamp)) < 300
return fresh and hmac.compare_digest("sha256=" + mac.hexdigest(), signature)
请在进行任何 JSON 解析之前,按收到时的原样对原始正文计算签名。五分钟的时间窗口由您自行决定;它可防止旧请求被重放。
投递只尝试一次,超时时间为 5 秒。不跟随重定向,解析到私有网络的地址会被丢弃。如果错过的事件很重要,请读取 get_status 来同步状态。
短链接
GET https://cliqer.io/api/timer/link/<code> 将短链接代码解析为对应的房间:{"ok": true, "data": {"roomId", "link"}};如果代码未知、已撤销或已过期,或密码错误,则返回 404 Link not found。对于设有密码的链接,请在 x-link-password 请求头中发送密码,切勿放在地址中。
Companion 与 Stream Deck
Cliqer Timer 房间没有 Companion 模块或 Stream Deck 插件。Bitfocus Companion 的 Generic HTTP 模块可以调用上述操作。Cliqer 桌面应用自带的计时器具备 REST API 和 Stream Deck 支持,参见 Timer(桌面版) 和 主机端计时器。
常见问题
密钥缺失、输入有误或不属于您:账户密钥仅适用于您拥有的房间。请检查请求头是否为 Authorization: Bearer <key>,且没有多余的空格。
房间所有者的套餐不包含 Timer API。参见 套餐与限制。
不可以。API 需要您所拥有房间的密钥,而演示房间不属于任何人。
请检查地址是否为 https、能否从互联网访问,并且能在 5 秒内响应且不发生重定向。如果您丢失了签名密钥,请重新设置;旧的签名密钥将失效。