SteveSignalsDocs

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 する

Webhook と実行ごとに 1 リクエスト。件数とトークンだけが入ります。

あなたが 2xx を返す

ボディを保存し、10 秒以内に応答します。残りの処理はバックグラウンドで行います。

あなたがページを読み取る

firstPageToken があるイベント名ごとに GET /api/public/v1/events?pageToken=… を呼びます。nextPageToken が null になるまで続けます。

広告トラッカーの実行の例です。ネットワークごとに 1 件ずつ、合計 3 件の新しい広告が見つかったため、ads.new に bySubEvent があります。ads.updated は 0 として載っています。

POST ボディ · 実行 Webhook · ads(HubSpot)正確な形のサンプル(実データはまだありません)
json
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": 1
28 },
29 "firstPageToken": "<page token: ads.new, page 1>"
30 },
31 "ads.updated": {
32 "total": 0,
33 "totalPages": 0,
34 "firstPageToken": null
35 }
36 }
37}
実行 Webhook
version
3
ボディのバージョン。Signals-Event-Version ヘッダーと同じ値です。
webhookId
string
この配信の ID。Signals-Webhook-Id ヘッダーと同じ値です。再試行でも変わりません。同じ POST の重複を捨てるのに使います。
type
'run.completed'
現在はこの値だけです。それ以外の値は未知として扱ってください。
eventType
'ads'|'reviews'|'social_post'|'mention'|'news'|'website'|'jobs'|'competitor'
実行のイベントファミリー。1 つの実行は 1 つのトラッカーなので、ファミリーも 1 つです。
sentAt
string
この試行の時刻(ISO 8601)。
run
object
実行の情報。下記をご覧ください。
pageSize
number
1 ページのイベント数。100 です。
events
object
実行のトラッカーが送れるイベント名ごとに 1 セクション。キーはイベント名(ads.new、jobs.removed など)です。total: 0 の名前も含め、すべての名前が載ります。ファミリーごとのイベント名をご覧ください。
run
id
string
実行 ID。実行の各イベントは、これを runId として持ちます。
trackerId
string
実行したトラッカー。常に入ります。
projectId
string|null
トラッカーのプロジェクト。実際の実行では常に入ります。null になるのはテスト配信だけです。
source
string
トラッカーのソース: ads、reviews、linkedin、x、instagram、linkedin_mentions、reddit_mentions、news、website、job_postings、competitor_discovery。
completedAt
string
実行の時刻(ISO 8601)。
competitor
object
{ name: string, domain: string | null, subjectKey: string }。各イベントのものと同じオブジェクトです。実際の実行では常に入ります。
events[name]
total
number
Webhook のフィルターを適用した後の、この名前のイベント数。
totalPages
number
total を 100 で割って切り上げた値。total が 0 なら 0。
bySubEventoptional
object
subEventType ごとの total。例: { "google_ad": 1, "meta_ad": 1 }。実行に複数のサブタイプ(広告ネットワークやレビューサイト)が混在するときだけ入ります。
firstPageToken
string|null
この名前の 1 ページ目を開くトークン。total が 0 なら null。

例のトークンはプレースホルダーです。実際のトークンは不透明な文字列です。解析したり変更したりしないでください。

イベントではなく件数を送る理由

1 回の実行で数千件見つかることもあります。POST は小さいまま、すぐに検証できます。イベントは自分のペースで読み取れ、同じページを何度でも読み直せます。Webhook のフィルターが変わらない限り、同じトークンは同じページを返します。

ファミリーごとのイベント名

セクションのキーはイベント名(各イベントの signalType)です。各名前は 1 つのアクションに対応します。実行には、そのファミリーのすべての名前がこの順で載り、見つからなかった名前は total: 0 になります。

eventTypeトラッカーの sourcesubEventTypenewupdatedremoved
adsadsgoogle_ad、meta_ad、linkedin_adads.newads.updated
reviewsreviewsg2_review、trustpilot_review、capterra_review、trustpilot_de_review、capterra_de_review、boxil_reviewreviews.newreviews.updated
social_postlinkedin、x、instagramlinkedin_post、x_post、instagram_postsocial.postsocial.post_updated
mentionlinkedin_mentions、reddit_mentionslinkedin_mention、reddit_mentionsocial.mentionsocial.mention_updated
newsnewsnews_articlenews.articlenews.article_updated
websitewebsitewebsite_changewebsite.page_addedwebsite.changed
jobsjob_postingsjob_postingjobs.newjobs.updatedjobs.removed
competitorcompetitor_discoverynew_competitormarket.new_competitormarket.competitor_updated

8 つのファミリーと 18 のサブタイプです。

  • removed の名前を送るのは求人だけです(jobs.removed、終了した求人)。他のトラッカーは送らないため、その実行 Webhook には removed のセクションがありません。
  • website.page_added は total: 0 として載ります。現在、Web サイトの実行に入るのは website.changed だけです。
  • bySubEvent が入るのは広告とレビューの実行で、複数のネットワークやサイトが見つかったときだけです。
  • engagement.*(LinkedIn エンゲージメント)は Webhook では送られません。

求人の実行では、3 つのアクションすべてが載ります。

POST ボディ · 実行 Webhook · jobs(Acme)正確な形のサンプル(実データはまだありません)
json
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 です。イベントタイプ一覧に、サブタイプごとのプラットフォームフィールドが載っています。

イベントを読み取る

bash
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 は送られません。

Webhook を追加ダイアログのイベントフィルター
イベントフィルターには、種類とそのサブタイプが並びます(画面は英語版)。

届くまでの流れ

実行が終わる

トラッカーがソースをチェックし、見つけたイベントを保存します。

ディスパッチャーが数える

1 分ごとにジョブが動きます。有効な Webhook ごとに、フィルターに一致する実行のイベントを数えます。一致が 0 件の実行はスキップします。

Signals があなたの URL に POST する

Webhook と実行ごとに、署名付きのリクエストを 1 回。下記のヘッダーが付きます。応答の制限時間は 10 秒です。

サーバーが 2xx を返す

どの 2xx でも配信済みになります。それ以外は再試行されます。再試行と失敗をご覧ください。

あなたがページを読み取る

API キーを使い、自分のペースで、30 日以内に読み取ります。

1 つのエンドポイントへの配信は 1 件ずつ、古い実行から送られます。応答の遅いエンドポイントは、後に続く実行を遅らせます。

ヘッダー

すべてのリクエストに、次のヘッダーが付きます。

ヘッダー例意味
Content-Typeapplication/json常に JSON です。
Signals-Event-Version3ボディの version。破壊的変更のときだけ変わります。
Signals-Webhook-Id配信ごとの UUIDボディの webhookId。同じ配信の再試行では変わりません。
Signals-Delivery-Attempt1試行回数。1 から 9。
Signals-Signaturet=<unix seconds>,v1=<hex>タイムスタンプと HMAC-SHA256 署名。署名を検証するをご覧ください。
Signals-Testtrueテスト配信のときだけ付きます。実際の配信には付きません。

ノーコードツールでの振り分け

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 で取得してください。