コンテンツにスキップ

Throk Webhook の設定方法:ルール作成・送信フォーマット・署名の検証

Webhook を使えば、API を何度もポーリングする必要はありません。ルールを設定しておくと、条件に合う投稿が Threads に現れたときに、Throk が投稿データを指定の URL へ POST します。よくある使い方は次のとおりです。

  • ブランドや商品が言及され、盛り上がり始めたときに、Slack、LINE、社内システムへ通知する
  • 話題の中で、いいね数、リプライ数、閲覧数がしきい値を超えた投稿をモニタリングする
  • 今まさにバズっている投稿を、データベースや CRM へ自動で取り込む

Webhook は 2 つの要素で構成されます。

  • エンドポイント(Endpoint):通知を受け取る URL。例:https://example.com/throk-webhook。エンドポイントごとに専用の署名シークレットがあります。
  • ルール(Rule):どの投稿を送信するかを決める条件。各ルールは 1 つのエンドポイントに属し、1 つのエンドポイントに複数のルールを設定できます。

Throk は 3 分ごとにすべてのルールをチェックします。条件に合う投稿は、投稿 1 件につき 1 イベントとしてエンドポイントに送信されます。同じ投稿が同じルールで送信されるのは 1 回だけです。

投稿にキーワードが含まれ、かつ設定したしきい値に達したときに送信します。

  • キーワードは 1 つのルールにつき 1 つです。照合方法はキーワード検索と同じで、中国語は文字単位、英語は単語単位で照合します。
  • チェック対象は、直近 24 時間以内に投稿されたものです。
  • しきい値は少なくとも 1 つ設定してください。最低値は、いいね数 ≥ 10、リプライ数 ≥ 5、閲覧数 ≥ 1,000 です。

キーワードを設定せず、指定した期間内に投稿され、しきい値に達した投稿を送信します。今まさにバズっているコンテンツを見つけるのに向いています。

  • チェック対象は、過去 1〜72 時間以内に投稿されたものです(lookbackHours で設定)。
  • しきい値は少なくとも 1 つ設定してください。最低値は、いいね数 ≥ 500、リプライ数 ≥ 100、閲覧数 ≥ 5,000 です。
  • 同じルール内のしきい値は「かつ」の関係です。 例:いいね数 ≥ 100 かつリプライ数 ≥ 10。
  • 異なるルールは互いに影響しません。 1 件の投稿が 2 つのルールに合致した場合は、2 つのイベントが送信されます。
  • 投稿の言語で絞り込めます。 zh(中国語すべて、デフォルト)、zh-Hant(繁体字中国語)、zh-Hans(簡体字中国語)、yue(広東語)、ja(日本語)、ko(韓国語)を指定できます。投稿者の所在地ではなく、投稿ごとの言語で判定します。zh は zh-Hant・zh-Hans・yue を含みます。
  • リプライも対象です。 リプライがルールに合致して送信されることもあります。イベントの is_reply フィールドで区別できます。
  • ルールごとに送信数を制限できます。 hourlyLimit は 1 時間あたり(UTC の毎正時で区切り)の上限、dailyLimit は連続する任意の 24 時間の上限で、暦日ごとの上限ではありません。指定しない場合は無制限です。上限を超える場合は反応の多い投稿から送信します。いいね数のしきい値があればいいね数、なければリプライ数、それもなければ閲覧数で比べ、同じ数なら新しい投稿を優先します。それ以外の投稿は保留されません。チェックのたびに現在の数で並べ直し、対象期間内に順番が来れば送信されますが、対象期間を過ぎると送信も課金もされません。dailyLimit だけを指定すると 1 回のチェックで使い切り、最大 24 時間送信されないことがあるため、hourlyLimit も指定することをおすすめします。
  • 閲覧数のしきい値は遅れて発火します。 投稿の閲覧数は通常、投稿から数時間後にデータが反映されます。そのため、閲覧数のしきい値を設定したルールは、いいね数やリプライ数だけを見るルールより送信が遅れます。

開発者プラットフォームで設定する

Section titled “開発者プラットフォームで設定する”
  1. 開発者プラットフォームにログインし、エンドポイントとルールを開きます。
  2. エンドポイントを追加を押し、URL を入力して作成を押します。
  3. エンドポイントの下にある + ルールを追加 を押し、キーワードまたは人気しきい値を選びます。言語としきい値を設定し(人気しきい値の場合は「過去…時間」も設定します)、追加を押します。
  4. エンドポイントのテストを押して、サーバーがイベントを受信できることを確認します。エンドポイントを作成すればルールがなくてもテストできます。テストイベントではクレジットを消費しません。
  5. エンドポイントを展開すると 署名シークレット が表示されます。これを使って署名を検証します。

開発者プラットフォームの Webhook 通知ページ:エンドポイントにキーワードルールを追加し、言語と、いいね数・リプライ数・閲覧数のしきい値を設定する

送信したすべてのイベントと、受信側のレスポンスステータスは送信履歴ページで確認できます。失敗したイベントは再送信できます。

エンドポイントとルールは API でも管理できます。どのリクエストにも API キーが必要です。

メソッドとパス 用途
GET /webhook/endpoints エンドポイント、署名シークレット(secret)、ルールの一覧を取得
POST /webhook/endpoints エンドポイントを作成
DELETE /webhook/endpoints/{endpoint_id} エンドポイントを削除(配下のすべてのルールも削除)
POST /webhook/endpoints/{endpoint_id}/rules エンドポイントにルールを作成
DELETE /webhook/rules/{rule_id} ルールを削除
POST /webhook/endpoints/{endpoint_id}/test テストイベントを 1 件送信(無料)

エンドポイントを作成する:

ターミナルウィンドウ
curl -X POST 'https://premium-api.throk.ai/webhook/endpoints' \
-H 'Authorization: Bearer sk-throk-...' \
-H 'Content-Type: application/json' \
-d '{"url": "https://example.com/throk-webhook"}'

キーワードルールを作成する(いいね数 ≥ 100 の日本語の投稿):

ターミナルウィンドウ
curl -X POST 'https://premium-api.throk.ai/webhook/endpoints/{endpoint_id}/rules' \
-H 'Authorization: Bearer sk-throk-...' \
-H 'Content-Type: application/json' \
-d '{"keyword": "ダイエット", "likeCount": 100, "language": "ja"}'

人気しきい値ルールを作成する(過去 6 時間以内、いいね数 ≥ 1,000 の投稿):

ターミナルウィンドウ
curl -X POST 'https://premium-api.throk.ai/webhook/endpoints/{endpoint_id}/rules' \
-H 'Authorization: Bearer sk-throk-...' \
-H 'Content-Type: application/json' \
-d '{"likeCount": 1000, "lookbackHours": 6}'

ルールのフィールド:

フィールド 説明
keyword キーワード。空欄にすると人気しきい値ルールになります
likeCount、replyCount、viewCount いいね数、リプライ数、閲覧数のしきい値。少なくとも 1 つ指定します
hourlyLimit、dailyLimit このルールが 1 時間あたり(UTC の毎正時で区切り)、および連続する任意の 24 時間に送信するイベントの上限。最小値は 1。指定しない場合は無制限です
lookbackHours 過去何時間以内に投稿されたものをチェックするか。1〜72。人気しきい値ルールでは必須です。キーワードルールは常に直近 24 時間をチェックするため指定できません(400 を返します)
language 投稿の言語:zh、zh-Hant、zh-Hans、yue、ja、ko(大文字・小文字は区別しません)。デフォルトは zh。レスポンスでは常にこの表記で返ります

フィールド名はスネークケース(例:like_count、lookback_hours)でも指定できます。レスポンスは常に上の表の表記です。

ルールは変更できません。調整したい場合は、削除してから作り直してください(開発者プラットフォームでは直接編集できます)。

各イベントは POST でエンドポイントに送信され、本文は JSON です。

{
"post": {
"url": "https://threads.com/post/DaXXXXXX",
"code": "DaXXXXXX",
"caption": "投稿の本文……",
"is_reply": false,
"like_count": 1700,
"reply_count": 293,
"repost_count": 40,
"reshare_count": 180,
"impression_count": 254300,
"post_timestamp": 1776760127,
"media_url": ["https://media01.throk.ai/media/..."]
},
"user": {
"username": "...",
"full_name": "...",
"profile_picture": "https://media01.throk.ai/profile/..."
},
"rule": {
"id": "9b2f6c1e-…",
"type": "keyword",
"keyword": "ダイエット"
}
}
  • 数値は送信時点のスナップショットです。その後投稿の数値が伸びても、更新は送信されません。
  • repost_count にはリポストと引用が含まれます。impression_count は、閲覧数のデータがまだない場合は null になります。
  • rule はこのイベントを送信したルールです。id はルール ID(ルール作成時に返される値と同じ)、type は keyword(キーワードルール)または trending(人気しきい値ルール)で、人気しきい値ルールでは keyword が null です。1 つの投稿が複数のルールに合致した場合は、ルールごとにイベントが 1 件ずつ送信されます。
  • テストイベントの rule は {"id": "test", "type": "test", "keyword": null} なので、本番のイベントと区別できます。

すべてのイベントには署名が付いています。これにより、リクエストが確かに Throk から送られたもので、内容が改ざんされていないことを確認できます。

  • 署名のシークレットは、エンドポイントの 署名シークレット です(開発者プラットフォームでエンドポイントを展開すると表示されます。GET /webhook/endpoints のレスポンスの secret フィールドでも確認できます)。
  • 署名はリクエストヘッダー X-Throk-Signature に含まれ、形式は t=<UNIX タイムスタンプ>,v1=<署名> です。
  • 検証方法:署名シークレットをキーとして <タイムスタンプ>,<生のリクエストボディ> の HMAC-SHA256(16 進数)を計算し、v1 と照合します。あわせて、リプレイ攻撃を防ぐため、タイムスタンプが数分以内であることも確認してください。

Node.js の例:

import crypto from 'node:crypto';
// rawBody: 生のリクエストボディ(文字列)、header: X-Throk-Signature の値
function verify(rawBody, header, secret) {
const fields = header.split(',').map((p) => p.split('='));
const t = Number(fields.find(([k]) => k === 't')?.[1]);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; // 5 分以内のリクエストのみ受け付ける
const expected = Buffer.from(
crypto.createHmac('sha256', secret).update(`${t},${rawBody}`).digest('hex'),
);
// シークレットの切り替え中は v1 が複数含まれることがあるので、いずれか 1 つと一致すれば OK
return fields
.filter(([k]) => k === 'v1')
.some(([, sig]) => {
const got = Buffer.from(sig);
return got.length === expected.length && crypto.timingSafeEqual(got, expected);
});
}

署名は生のリクエストボディ(raw body)で計算してください。いったん JSON としてパースしてから文字列に戻したものは使わないでください。

  • できるだけ早く HTTP 2xx を返してください。時間のかかる処理はバックグラウンドで実行してください。
  • 2xx を返さなかったイベントは指数バックオフで自動的に再試行されます(最大 10 回)。開発者プラットフォームの送信履歴から手動で再送信することもできます。
  • 1 つのエンドポイントが受信するイベントは 60 秒あたり最大 1,000 件で、超えた分は後から送信されます。
  • 本番のイベントには X-Convoy-Idempotency-Key ヘッダーが付き(テストイベントには付きません)、同じイベントの再試行では値が変わりません。このヘッダー(または投稿の code)で重複を排除し、二重処理を防いでください。
  • イベントを 1 件送信するごとに 20 クレジットを消費します。クレジットは API の呼び出しと同じアカウントのものを共有します。同じ投稿が同じルールで課金されるのは 1 回だけです。課金はイベントの送信時点で発生し、受信側の応答結果には左右されません。エンドポイントが正常に受信できる状態にしておいてください。
  • エンドポイントとルールの作成・削除、テストイベントではクレジットを消費しません。
  • クレジットが不足すると、イベントの送信は一時停止されます。クレジットを補充すると、まだチェック対象期間内にある投稿は次回のチェックで送信されます。
  • Webhook を含まないプランにダウングレードした場合、既存のルールは残りますが、発火しなくなります。
  • Webhook の消費は クレジット使用履歴に表示され、API の種類は webhook です。

Webhook には一時停止のスイッチはありません。送信を止めるには、ルールまたはエンドポイントを削除してください。エンドポイントを削除すると、配下のすべてのルールも削除されます。

Webhook の機能紹介と対応プランは Throk Webhook をご覧ください。