/v1/account/webhook-endpoints

account/webhook-endpoints

Webhook:モニタリングが新しいシグナルを送る先と、その検証方法。

コストと制限

コストと制限
内容 クレジット
Webhookエンドポイントと配信の管理 無料

制限:1分あたり 30 リクエスト。 作成、更新、削除:1分あたり 10 回。 チェック、テスト、新しいシークレット:1分あたり 6 回。

管理者トークンまたはAPIキー

エンドポイント

メソッド
メソッド パス 用途 アクセス
GET /v1/account/webhook-endpoints すべてのWebhookエンドポイント(アーカイブ済みを除く)。 APIキーまたは管理者トークン
POST /v1/account/webhook-endpoints Webhookエンドポイントを作成。 管理者トークン
POST /v1/account/webhook-endpoints/{id}/verify 検証。 APIキーまたは管理者トークン
POST /v1/account/webhook-endpoints/{id}/test テストメッセージを送信。 APIキーまたは管理者トークン
POST /v1/account/webhook-endpoints/{id}/rotate-secret 新しい署名シークレット。 管理者トークン
POST /v1/account/webhook-endpoints/{id}/enable 有効化。 管理者トークン
POST /v1/account/webhook-endpoints/{id}/disable 無効化。 管理者トークン
DELETE /v1/account/webhook-endpoints/{id} アーカイブ。 管理者トークン
GET /v1/account/webhook-deliveries 直近 50 件の配信。 APIキーまたは管理者トークン
POST /v1/account/webhook-deliveries/{id}/retry 失敗した配信を再送。 APIキーまたは管理者トークン
GET /v1/account/webhook-events 直近 50 件のイベント。 APIキーまたは管理者トークン

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

curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints" \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM-Sync",
    "url": "https://hooks.example.com/handelsregister",
    "headers": {
        "X-Receiver-Token": "YOUR_RECEIVER_TOKEN"
    }
}'
パラメータ
名前 型 説明 例
Idempotency-Keyヘッダー 文字列必須 操作ごとに一意の値。できればUUID。Idempotency-Keyを参照。制限: 1~128 文字 req-20260802-01
nameボディ 文字列必須 自分で参照するための名前。制限: 1~120 文字 CRM-Sync
urlボディ 文字列 (uri)必須 あなたのサーバーのアドレス:公開されていて、ポート443のhttps、IPアドレスではなくホスト名。制限: 1~2,048 文字 https://hooks.example.com/handelsregister
headersボディ オブジェクト任意 すべてのメッセージとともに送られるカスタムヘッダー。例えばあなたのサーバー用のトークン。制限: 10 件以下 {"X-Receiver-Token":"YOUR_RECEIVER_TOKEN"}
1{2  "endpoint": {3    "id": "wep_01m6b3j1g0cdz98hw8zdefbf52",4    "name": "CRM-Sync",5    "url": "hooks.example.com/…",6    "status": "pending_verification",7    "verified_at": null,8    "header_names": [9      "X-Receiver-Token"10    ],11    "consecutive_failures": 0,12    "created_at": "2026-11-01T08:28:01+00:00"13  },14  "signing_secret": "whsec_…",15  "meta": {16    "message": "Endpoint created. Store the signing secret now — it is shown only once.",17    "request_credit_cost": 0,18    "credits_remaining": 14519  }20}
201 · レスポンス例:新しいWebhookエンドポイント(シークレットはここでは短縮)

検証

1{2  "id": "msg_01m6b3jsqq7ntwzkdj099ayraz",3  "type": "endpoint.verification",4  "timestamp": "2026-11-01T08:28:26.743Z",5  "schema_version": 1,6  "data": {7    "challenge": "189fb34b2af819bb13cb47d9806dbf30"8  }9}
検証中にあなたのサーバーが受け取るメッセージ
curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01m6b3j1g0cdz98hw8zdefbf52/verify" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
1{2  "verified": true,3  "endpoint": {4    "id": "wep_01m6b3j1g0cdz98hw8zdefbf52",5    "name": "CRM-Sync",6    "url": "hooks.example.com/…",7    "status": "active",8    "verified_at": "2026-11-01T08:28:26+00:00",9    "header_names": [10      "X-Receiver-Token"11    ],12    "consecutive_failures": 0,13    "created_at": "2026-11-01T08:28:01+00:00"14  },15  "meta": {16    "request_credit_cost": 0,17    "credits_remaining": 14518  }19}
200 · 検証成功時のレスポンス例
1{2  "delivery": {3    "id": "del_01m6b3jsyrnc3sz1mt31dq6107",4    "message_id": "msg_01m6b3jsynxzhvagm7n2nq7mpv",5    "event_id": "evt_01m6b3jsynxzhvagm7n2nq7mpt",6    "event_type": "endpoint.test",7    "endpoint_id": "wep_01m6b3j1g0cdz98hw8zdefbf52",8    "status": "succeeded",9    "attempts": 1,10    "last_status_code": 200,11    "last_error_category": null,12    "next_attempt_at": "2026-11-01T08:28:26+00:00",13    "succeeded_at": "2026-11-01T08:28:26+00:00",14    "created_at": "2026-11-01T08:28:26+00:00"15  },16  "meta": {17    "request_credit_cost": 0,18    "credits_remaining": 14519  }20}
200 · テストメッセージのレスポンス例

署名を検証する

ヘッダー
ヘッダー 意味
webhook-id メッセージのID(msg_…)。再試行でも同じです。重複の検出に使ってください。
webhook-timestamp この配信試行の時刻(Unix秒)。
webhook-signature v1,<Base64>形式の1つ以上の署名(スペース区切り)。
import base64, hashlib, hmac, time

def verify_webhook(secret: str, headers: dict, body: bytes) -> bool:
    msg_id = headers["webhook-id"]
    timestamp = headers["webhook-timestamp"]
    # 5分より古いメッセージを拒否する
    if abs(time.time() - int(timestamp)) > 300:
        return False
    key = base64.b64decode(secret.removeprefix("whsec_"))
    signed = f"{msg_id}.{timestamp}.".encode() + body
    expected = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
    # シークレットのローテーション中は、ヘッダーに署名が2つ入ります
    for part in headers["webhook-signature"].split(" "):
        version, _, signature = part.partition(",")
        if version == "v1" and hmac.compare_digest(signature, expected):
            return True
    return False

ペイロード

フィールド
フィールド 意味
id メッセージのID。ヘッダーwebhook-idと同じ。
event_id イベントのID(evt_…)。
type イベントの種類(下記参照)。
timestamp 私たちがイベントを検出した時刻(UTC)。
schema_version 構造のバージョン。現在は1。
data イベントのデータ。
イベントの種類
イベントの種類 意味
organization.signal.detected モニターが新しいシグナルを見つけた。data.signalはsignalsのシグナルと同じ構造で、さらにdata.monitorと、data.links.signalにAPI内のシグナルへのリンクが付きます。
organization.signal.sample アカウント › モニタリングから送られる、企業の実際の履歴からの例。構造は上記と同じで、data.sample: trueが付きます。
endpoint.test /testによるテストメッセージ。
endpoint.verification 検証中のチャレンジ。
1{2  "id": "msg_01m65pqg9x0176cteqvtxw68sa",3  "event_id": "evt_01m65pqg9sx7mwmw0edc1mfbbe",4  "type": "organization.signal.sample",5  "timestamp": "2026-10-30T06:07:37.000Z",6  "schema_version": 1,7  "data": {8    "monitor": {9      "id": "mon_01m65pn3vm11sjjp1j076cbvec",10      "type": "organization.signals"11    },12    "sample": true,13    "signal": {14      "event": {15        "id": "36c7c8fddf99bb0299d6815bcaa01013",16        "topic": "TRANSFORMATIONS",17        "topic_name": {18          "de": "Umwandlungen & M&A",19          "en": "Transformations & M&A"20        },21        "occurred_on": "2022-12-22",22        "announced_on": "2023-08-10",23        "date_basis": "SOURCE_EVENT"24      },25      "organization": {26        "type": "ORGANIZATION",27        "entity_id": "94eb910fef13f94585c48c263fa446d4",28        "current_profile": {29          "name": "Hetzner Online GmbH",30          "registration": {31            "register_type": "HRB",32            "register_number": "6089",33            "court": "Ansbach",34            "register_locality": "Ansbach",35            "registration_authority_id": "D3201",36            "register_entity_name": "Ansbach HRB 6089"37          },38          "legal_form": {39            "name": {40              "de": "Gesellschaft mit beschränkter Haftung"41            },42            "short": {43              "de": "GmbH"44            }45          },46          "seat": {47            "city": "Gunzenhausen"48          },49          "status": {50            "code": "ACTIVE"51          }52        }53      },54      "parties": {55        "counterparty": {56          "entity": {57            "type": "ORGANIZATION",58            "entity_id": "dd4d2d6854b2dbd1ffce74e669f3852e",59            "current_profile": {60              "name": "Headtrip GmbH",61              "registration": {62                "register_type": "HRB",63                "register_number": "33432",64                "court": "Nürnberg",65                "register_locality": "Nuremberg",66                "registration_authority_id": "D3310",67                "register_entity_name": "Nürnberg HRB 33432"68              },69              "legal_form": {70                "name": {71                  "de": "Gesellschaft mit beschränkter Haftung"72                },73                "short": {74                  "de": "GmbH"75                }76              },77              "seat": {78                "city": "Nürnberg"79              },80              "status": {81                "code": "INACTIVE"82              }83            }84          },85          "relationship": "TRANSFERRING_COMPANY"86        }87      },88      "register_entry": {89        "entry_number": "3",90        "entry_date": "2023-08-10",91        "description_text": "Verschmelzung zur Aufnahme der Headtrip GmbH",92        "context": "PRIMARY",93        "flags": []94      },95      "source": {96        "kind": "COMMERCIAL_REGISTER"97      },98      "details": {99        "schema": "TRANSFORMATION",100        "kind": "MERGER",101        "specifics": {102          "merger_target": "ABSORPTION"103        },104        "direction": "INCOMING",105        "is_cross_border": false,106        "resolution_date": "2022-12-22",107        "agreement_date": "2022-12-22"108      }109    },110    "links": {111      "signal": "https://handelsregister.ai/api/v1/signals/36c7c8fddf99bb0299d6815bcaa01013"112    }113  }114}
Hetzner Online GmbH(Ansbach HRB 6089)のメッセージ例:履歴からの例として送られた、Headtrip GmbH(Nürnberg HRB 33432)の合併

配信と再試行

すべてのメッセージを少なくとも1回は配信しますが、順序は固定されていません。重複はwebhook-idで検出してください。すぐに応答し、メッセージの処理はその後に行ってください。
配信のステータス
ステータス 意味
withheld チェックの課金を待っている。
pending 送信を待っている。
in_flight 現在送信中。
retry_wait 次の試行を待っている。
succeeded 配信済み。
exhausted すべての試行が失敗した。
blocked_endpoint Webhookエンドポイントが現在何も受け取れない。
cancelled キャンセル済み。例えばメッセージの期限が切れた場合。

有効化、無効化、アーカイブ

curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01m6b3j1g0cdz98hw8zdefbf52/disable" \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"

エラー

エラー
ステータス 原因 対処法
400 api_keyがURLにある。 キーをヘッダーx-api-keyで送る。
400 URLが送信先として許可されていない、ヘッダーが許可されていない、最大数に達している、またはWebhookエンドポイントが有効でない。meta.messageに理由がある。 値を修正するか、先に検証する。
400 Idempotency-Keyの形式が無効。 形式を修正する。例えばUUIDを使う。
401 APIキーもトークンもないか、無効。 キーをヘッダーx-api-keyで送る。
403 Bearerトークンに権限account:readがない。 APIキーか、account:read付きのトークンを使う。
403 アカウントのメールアドレスがまだ確認されていないか、アカウントがロックされている。 確認メールのリンクを開く。アカウントがロックされている場合はサポートが対応できる。
403 この呼び出しには管理者トークンが必要。APIキーでも、他のトークンでも足りない。 Authorization: Bearerと管理者トークンで送る。
403 Bearerトークンに権限monitoring:manageがない。 APIキーか管理者トークンを使う。
404 このIDのWebhookエンドポイントまたは配信がない。 IDを確認する。
409 Idempotency-Keyがすでに別のデータで使われている、24時間より古い、またはまだ処理中。 新しいキーを使うか、少し待つ。
422 nameやurlなど、値がないか無効。errorsにそのフィールドが示される。 値を修正し、新しいキーで再試行する。
422 検証に失敗した。 チャレンジヘッダーと2xxステータスを確認し、新しいキーで再試行する。
428 ヘッダーIdempotency-Keyがない。 ヘッダーを送る。
429 リクエストが多すぎる。 Retry-Afterの後に再試行する。
503 検証、テスト、再送が一時的に利用できない。 少し後に再試行する。
1{2  "error": "invalid_request",3  "meta": {4    "message": "The endpoint is not active.",5    "request_credit_cost": 0,6    "credits_remaining": 1457  }8}
400 · まだ検証されていないWebhookエンドポイントはテストメッセージを受け取れない