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 キーは、自分が所有するルームですべての操作ができます。ルームに専用のキーを持たせることもでき、各キーには次の 3 つの権限から必要なものを付与します。
| 権限 | 許可される操作 |
|---|---|
| 読み取り | get_ アクションと export。 |
| ショーコール | トランスポート、時間、ブラックアウト、オンエア、メッセージ。 |
| 編集 | 削除、インポート、raw インテント、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、または秒数の数値だけで指定します。amount の代わりに seconds も使え、マイナス記号を付けると逆方向になります。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 | ルームがゴミ箱にある。先に復元してください。 |
レート制限: キーごとに 1 分あたり 100 回です。キーなしの呼び出しはアドレスごとにカウントされます。各応答には RateLimit-Limit、RateLimit-Remaining、RateLimit-Reset(次の 1 分が始まるまでの秒数)が含まれます。
Webhook
アドレスを設定する
https の url を指定して webhook を呼び出します。応答には whsec_ で始まる secret が含まれます。一度しか表示されないため、必ず保存してください。
イベントを受信する
ルームで何かが起きると、Cliqer Timer がそのアドレスに POST を送信します。
署名を検証する
すべてのリクエストを、信頼する前に検証してください。
解除する
url を指定せずに webhook を呼び出します。アドレスとシークレットの両方が削除されます。
| イベント | タイミング |
|---|---|
timerStarted | タイマーが開始したとき。 |
timerEnded | タイマーがゼロになったとき。 |
wrapUpYellow | タイマーが黄色の終了予告ポイントに達したとき。 |
wrapUpRed | タイマーが赤色の終了予告ポイントに達したとき。 |
messageShown | メッセージが表示されたとき。 |
ボディは {"event", "roomId", "timestamp", "payload"} です。x-cliqer-timestamp ヘッダーには Unix 時間(秒)が入り、x-cliqer-signature には sha256= に続けて、シークレットをキーとした <timestamp>.<body> の HMAC-SHA256 の 16 進値が入ります。
# 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 分という時間枠は任意で決められます。古いリクエストが再送(リプレイ)されるのを防ぐためのものです。
配信は 1 回のみで、タイムアウトは 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 秒以内に応答するか確認してください。シークレットをなくした場合は、もう一度設定してください。古いシークレットは使えなくなります。