Webhook
Webhook の仕組み
トラッカーの実行ごとに件数とページトークンだけを持つ小さな POST が 1 回届き、イベントは API から 100 件ずつ読み取ります。アクションごとのイベント名、フィルター、ヘッダー、配信の保証を説明します。
Webhook は、トラッカーの実行で新しいイベントが見つかったことを、あなたの URL に知らせます。ポーリングは不要です。あなたは HTTPS エンドポイントを用意します。Signals はそこに小さな実行 Webhook を 1 回 POST し、あなたは 2xx を返します。イベント本体は、その後 API から 100 件ずつ読み取ります。
- リクエスト
- Webhook と実行の組み合わせごとに
POSTを 1 回。Content-Type: application/json - ボディ
- 実行 Webhook(
versionは3)。実行の情報と、イベント名ごとのtotal、totalPages、firstPageToken。イベント本体は入りません。約 1〜2 KB - イベント
- API キーで
GET /api/public/v1/events?pageToken=…。1 ページに完全なイベントが最大 100 件。実行のイベントを読むをご覧ください - タイミング
- チェック完了から数分後。一致するイベントがない実行では何も送られません
- スコープ
- 組織ごと。エンドポイントは最大 5 件
- フィルター
- イベント、アクション、競合、プロジェクト。空ならすべて。AND で組み合わせ
- 配信
- 最低 1 回。POST は
webhookId、各イベントはeventIdで重複を排除してください - コスト
- 無料。Webhook でクレジットは消費しません
- 送信されないもの
- LinkedIn エンゲージメント(Pull API のみ)
送信される内容
トラッカーのチェック 1 回が 1 つの実行です。実行が終わり、フィルターに一致するイベントが 1 件以上あると、Signals はその実行について Webhook に POST を 1 回送ります。POST には、イベント名ごとの件数と、イベントを読み取るためのトークンが入ります。
Signals が実行 Webhook を POST する
あなたが 2xx を返す
あなたがページを読み取る
firstPageToken があるイベント名ごとに GET /api/public/v1/events?pageToken=… を呼びます。nextPageToken が null になるまで続けます。広告トラッカーの実行の例です。ネットワークごとに 1 件ずつ、合計 3 件の新しい広告が見つかったため、ads.new に bySubEvent があります。ads.updated は 0 として載っています。
1{2 "version": 3,3 "webhookId": "7fc0937d-6f0f-56c3-b6cf-5090cbb43015",4 "type": "run.completed",5 "eventType": "ads",6 "sentAt": "2026-10-27T20:29:55.624Z",7 "run": {8 "id": "b0b5b63b-fc3d-4eef-84ab-879e2335c06d",9 "trackerId": "3c8918c2-7011-4518-9185-31344c83861f",10 "projectId": "2738158a-08fd-4fc4-912d-43d4c328bc10",11 "source": "ads",12 "completedAt": "2026-10-27T20:29:00.624Z",13 "competitor": {14 "name": "HubSpot",15 "domain": "hubspot.com",16 "subjectKey": "google:AR10072600183532683265@-|meta:https://www.facebook.com/hubspot|linkedin:hubspot"17 }18 },19 "pageSize": 100,20 "events": {21 "ads.new": {22 "total": 3,23 "totalPages": 1,24 "bySubEvent": {25 "google_ad": 1,26 "meta_ad": 1,27 "linkedin_ad": 128 },29 "firstPageToken": "<page token: ads.new, page 1>"30 },31 "ads.updated": {32 "total": 0,33 "totalPages": 0,34 "firstPageToken": null35 }36 }37}
versionSignals-Event-Version ヘッダーと同じ値です。webhookIdSignals-Webhook-Id ヘッダーと同じ値です。再試行でも変わりません。同じ POST の重複を捨てるのに使います。typeeventTypesentAtrunpageSize100 です。eventsads.new、jobs.removed など)です。total: 0 の名前も含め、すべての名前が載ります。ファミリーごとのイベント名をご覧ください。idrunId として持ちます。trackerIdprojectIdnull になるのはテスト配信だけです。sourceads、reviews、linkedin、x、instagram、linkedin_mentions、reddit_mentions、news、website、job_postings、competitor_discovery。completedAtcompetitor{ name: string, domain: string | null, subjectKey: string }。各イベントのものと同じオブジェクトです。実際の実行では常に入ります。totaltotalPagestotal を 100 で割って切り上げた値。total が 0 なら 0。bySubEventoptionalsubEventType ごとの total。例: { "google_ad": 1, "meta_ad": 1 }。実行に複数のサブタイプ(広告ネットワークやレビューサイト)が混在するときだけ入ります。firstPageTokentotal が 0 なら null。例のトークンはプレースホルダーです。実際のトークンは不透明な文字列です。解析したり変更したりしないでください。
イベントではなく件数を送る理由
1 回の実行で数千件見つかることもあります。POST は小さいまま、すぐに検証できます。イベントは自分のペースで読み取れ、同じページを何度でも読み直せます。Webhook のフィルターが変わらない限り、同じトークンは同じページを返します。
ファミリーごとのイベント名
セクションのキーはイベント名(各イベントの signalType)です。各名前は 1 つのアクションに対応します。実行には、そのファミリーのすべての名前がこの順で載り、見つからなかった名前は total: 0 になります。
eventType | トラッカーの source | subEventType | new | updated | removed |
|---|---|---|---|---|---|
ads | ads | google_ad、meta_ad、linkedin_ad | ads.new | ads.updated | |
reviews | reviews | g2_review、trustpilot_review、capterra_review、trustpilot_de_review、capterra_de_review、boxil_review | reviews.new | reviews.updated | |
social_post | linkedin、x、instagram | linkedin_post、x_post、instagram_post | social.post | social.post_updated | |
mention | linkedin_mentions、reddit_mentions | linkedin_mention、reddit_mention | social.mention | social.mention_updated | |
news | news | news_article | news.article | news.article_updated | |
website | website | website_change | website.page_added | website.changed | |
jobs | job_postings | job_posting | jobs.new | jobs.updated | jobs.removed |
competitor | competitor_discovery | new_competitor | market.new_competitor | market.competitor_updated |
8 つのファミリーと 18 のサブタイプです。
removedの名前を送るのは求人だけです(jobs.removed、終了した求人)。他のトラッカーは送らないため、その実行 Webhook にはremovedのセクションがありません。website.page_addedはtotal: 0として載ります。現在、Web サイトの実行に入るのはwebsite.changedだけです。bySubEventが入るのは広告とレビューの実行で、複数のネットワークやサイトが見つかったときだけです。engagement.*(LinkedIn エンゲージメント)は Webhook では送られません。
求人の実行では、3 つのアクションすべてが載ります。
1{2 "version": 3,3 "webhookId": "ab78fcb4-5d5d-5224-9bc7-1a7025550b24",4 "type": "run.completed",5 "eventType": "jobs",6 "sentAt": "2026-10-29T06:03:07.903Z",7 "run": {8 "id": "5d2f7a14-9c3b-4e68-8f21-b7c4a0e19d36",9 "trackerId": "b13a7c58-02d4-4e9f-8a61-5f3c9e0d2b74",10 "projectId": "2738158a-08fd-4fc4-912d-43d4c328bc10",11 "source": "job_postings",12 "completedAt": "2026-10-29T06:02:12.903Z",13 "competitor": {14 "name": "Acme",15 "domain": "acme.com",16 "subjectKey": "jobs:acme.com"17 }18 },19 "pageSize": 100,20 "events": {21 "jobs.new": {22 "total": 1,23 "totalPages": 1,24 "firstPageToken": "<page token: jobs.new, page 1>"25 },26 "jobs.updated": {27 "total": 1,28 "totalPages": 1,29 "firstPageToken": "<page token: jobs.updated, page 1>"30 },31 "jobs.removed": {32 "total": 1,33 "totalPages": 1,34 "firstPageToken": "<page token: jobs.removed, page 1>"35 }36 }37}
ページの各イベントはイベントの形で、version は 1 です。イベントタイプ一覧に、サブタイプごとのプラットフォームフィールドが載っています。
イベントを読み取る
1curl "$SIGNALS_HOST/api/public/v1/events?pageToken=$TOKEN" \2 -H "x-api-key: $SIGNALS_API_KEY"
レスポンスの items に最大 100 件のイベントと、nextPageToken が入ります。nextPageToken が null になるまで呼び続けます。レスポンスの全項目、エラー、そのまま使えるループは実行のイベントを読むにあります。
ページと Pull API の違い
ページの各要素はイベントの形(eventId、eventType、adsResponse など)です。pageToken なしの Pull API は signal.v1 を返します。両者の対応は Pull API とキーに載っています。
受け取るイベント
各 Webhook には 4 つのフィルターがあります。フィルターが空なら「すべて」を意味します。フィルターは AND で組み合わせます。イベントは 4 つすべてに一致する必要があります。フィルターは POST の件数と、ページのイベントの両方に適用されます。たとえば google_ad だけに絞った Webhook では、ads.new は Google 広告だけになります。total は Google 広告の件数で、ページにも Google 広告だけが入ります。
| フィルター | 一致の対象 | 例 |
|---|---|---|
| イベント | イベントの種類(ads、reviews、social_post、mention、news、website、jobs、competitor)とサブタイプ(google_ad、g2_review など) | g2_review と trustpilot_review のみ |
| アクション | イベントの action: new、updated、removed | 終了した求人だけを知るために removed のみ |
| 競合 | 競合のドメイン | hubspot.com のみ |
| プロジェクト | トラッカーが属するプロジェクト | 「EMEA」プロジェクトのみ |
種類をまるごと選ぶと、そのすべてのサブタイプが送られます。サブタイプを選ぶと、種類の中で絞り込めます。実行のイベントが 1 件も一致しなければ、その実行の POST は送られません。
届くまでの流れ
実行が終わる
ディスパッチャーが数える
0 件の実行はスキップします。Signals があなたの URL に POST する
サーバーが 2xx を返す
2xx でも配信済みになります。それ以外は再試行されます。再試行と失敗をご覧ください。あなたがページを読み取る
1 つのエンドポイントへの配信は 1 件ずつ、古い実行から送られます。応答の遅いエンドポイントは、後に続く実行を遅らせます。
ヘッダー
すべてのリクエストに、次のヘッダーが付きます。
| ヘッダー | 例 | 意味 |
|---|---|---|
Content-Type | application/json | 常に JSON です。 |
Signals-Event-Version | 3 | ボディの version。破壊的変更のときだけ変わります。 |
Signals-Webhook-Id | 配信ごとの UUID | ボディの webhookId。同じ配信の再試行では変わりません。 |
Signals-Delivery-Attempt | 1 | 試行回数。1 から 9。 |
Signals-Signature | t=<unix seconds>,v1=<hex> | タイムスタンプと HMAC-SHA256 署名。署名を検証するをご覧ください。 |
Signals-Test | true | テスト配信のときだけ付きます。実際の配信には付きません。 |
ノーコードツールでの振り分け
Zapier、Clay、n8n はボディのキーで分岐できます。ファミリーは eventType、1 つのイベント名は events["ads.new"].total で分岐し、HTTP ステップでページの URL を呼びます。
配信の保証
- 最低 1 回。 同じ POST が複数回届くことがあります。たとえば、サーバーは受け取ったのにタイムアウトになった場合です。
webhookIdで重複を排除してください。 - イベントのキーは
eventId。 再配信では、同じ実行が新しいwebhookIdで送られます。また、同じページを 2 回読むこともあります。各イベントはeventIdで重複を排除してください。 - 順序は保証されません。 実行は古い順に送られますが、再試行された POST は新しい POST の後に届くことがあります。ページ内のイベントは
sequenceの順です。実行をまたいで順序が重要ならdetectedAtで並べ替えてください。 - 一時停止しても位置は保たれます。 再開や再度有効にするの後、その間に終わった実行も送られます。新しい Webhook に届くのは、作成した後に終わった実行だけです。それより前の履歴は Pull API で読み込んでください。
- リダイレクトには追従しません。 最終的な URL を Signals に登録してください。
- 無料。 Webhook とそのページでクレジットは消費しません。
LinkedIn エンゲージメント
LinkedIn エンゲージメントは Webhook では送られず、Slack にも投稿されません。Pull API で取得してください。