Download OpenAPI specification:
このガイドは、ゴリラセールスの Webhook を受信するエンドポイントを実装する開発者向けの資料です。 商談完了などのイベントが発生すると、あらかじめ登録した受信 URL へ、署名付きの HTTP POST リクエストが届きます。 この資料だけで、受信エンドポイントの実装・署名検証・動作確認まで完結できるよう構成しています。
署名方式は Standard Webhooks 準拠です。 Standard Webhooks に対応した検証ライブラリを利用して署名を検証することもできますし、後述のコード例のように自前で検証することもできます。
商談が完了すると、ゴリラセールスは商談データ・要約・BANT 情報をまとめたイベント(meeting.completed)を、
登録済みの受信 URL へ署名付き POST で通知します。受信側はこの通知を受け取り、自社の CRM やデータ基盤へ連携できます。
whsec_...)が発行され、受信側はこれを使ってリクエストの署名を検証します。2026-01-15T10:00:00.000Z)で送られます。通知される具体的なペイロード構造は、本ページ下部の Webhooks セクション(meeting.completed / test.ping)を参照してください。
localhost は登録できません)。whsec_...)が発行されます。signing secret(whsec_...)は、受信したリクエストが本当にゴリラセールスから送られたものかを検証するための鍵です。
「組織設定 > Webhook 連携」の各エンドポイント行の 「テスト送信」 から、実際に受信できるかを確認できます。 送信するイベント種別は 2 種類から選べます。
test.ping) — 軽量な疎通確認用のペイロード。まず受信できること・2xx を返せることの確認に使います。meeting.completed) — 架空のダミーデータ(固定 UUID・架空の会社名/氏名/要約/BANT/アクションアイテム)を含む、本番と同一構造の meeting.completed ペイロード。受信側のパース・マッピング実装を本番前に検証できます。補足:
通知されるイベントは次の 2 種類です。ペイロードの詳細スキーマは本ページ下部の Webhooks セクションを参照してください。
| イベント値 | 説明 | 発火契機 |
|---|---|---|
meeting.completed |
商談完了 | 商談が完了し、要約(サマリー)の生成が完了したとき。テスト送信では架空のサンプルデータで送られます。 |
test.ping |
疎通確認 | 管理画面からの手動テスト送信のときのみ。本番配信では送られません。 |
すべてのペイロードは JSON オブジェクトで、トップレベルに event(イベント種別文字列)・tenantId・occurredAt を含みます。
各リクエストには、Content-Type(application/json)に加えて、以下の署名関連ヘッダが付与されます。
| ヘッダ名 | 内容 |
|---|---|
webhook-id |
配信 ID(delivery ID)。署名対象であり、冪等化キーとしても使えます。 |
webhook-timestamp |
署名時刻(Unix 秒、文字列)。 |
webhook-signature |
v1,<base64 署名> 形式(スペースなし)。複数の署名がスペース区切りで入る場合があります。 |
受信側は、登録時に発行された signing secret を使い、以下の手順で HMAC を再計算して署名の一致を確認します。
署名対象文字列をピリオド区切りで組み立てます。
{webhook-id}.{webhook-timestamp}.{リクエストボディ生文字列}
ボディは受信した生の JSON 文字列をそのまま使います(再シリアライズしないでください)。
signing secret から whsec_ プレフィックスを外し、残りを base64 デコードしたバイト列を HMAC 鍵にします。
鍵で署名対象文字列を HMAC-SHA256 し、結果を base64 エンコードします。
受信した webhook-signature(v1,<署名> 形式)から、バージョン接頭辞 v1, を外した署名と、手順 3 の結果を定数時間比較します。
署名時刻は webhook-timestamp(Unix 秒)に載っています。リプレイ攻撃を防ぐため、
Standard Webhooks の推奨に従い、現在時刻との差が概ね ±5 分(300 秒)を超えるリクエストは拒否することを推奨します。
import { createHmac, timingSafeEqual } from "node:crypto";
/**
* Standard Webhooks 署名を検証する。
* @param rawBody 受信した生のリクエストボディ文字列(パース前)
* @param headers webhook-id / webhook-timestamp / webhook-signature
* @param secret 登録時に発行された signing secret(whsec_...)
*/
export function verifyWebhookSignature(
rawBody: string,
headers: {
"webhook-id": string;
"webhook-timestamp": string;
"webhook-signature": string;
},
secret: string,
): boolean {
const id = headers["webhook-id"];
const timestamp = headers["webhook-timestamp"];
const signatureHeader = headers["webhook-signature"];
// リプレイ対策: timestamp が許容範囲内かを確認(±300 秒)
const nowSec = Math.floor(Date.now() / 1000);
const sentSec = Number(timestamp);
if (!Number.isFinite(sentSec) || Math.abs(nowSec - sentSec) > 300) {
return false;
}
// 署名対象文字列
const signedContent = `${id}.${timestamp}.${rawBody}`;
// secret から whsec_ を外して base64 デコードしたバイト列を鍵にする
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = createHmac("sha256", key)
.update(signedContent, "utf8")
.digest("base64");
// webhook-signature は "v1,<sig> v2,<sig> ..." のようにスペース区切りで
// 複数入りうる。バージョンが v1 のエントリのみを対象に、定数時間で比較する。
return signatureHeader.split(" ").some((entry) => {
const [version, sig] = entry.split(",");
if (version !== "v1" || !sig) return false;
const a = Buffer.from(sig);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
});
}
webhook-id で冪等化する。 リトライにより、同一の配信が複数回届くことがあります。
webhook-id(配信 ID)を冪等化キーに使い、二重処理を防いでください。null 値がありえます。
未知のキーは無視し、null 許容フィールドは存在を前提にせず扱ってください。meeting.completed)408 / 429 を除く 4xx) → 失敗で確定し、リトライしません。Q. 通知が届きません。
test.ping) で疎通を確認し、受信側が 2xx を返せているかを切り分けてください。Q. 署名検証に失敗します。
webhook-timestamp の許容範囲(±5 分)でリクエストが拒否されていないか、サーバーの時刻同期(NTP)を確認してください。Q. 同じ商談の通知が複数回届きました。
webhook-id を冪等化キーに使い、二重処理を防いでください。商談が完了し、要約(サマリー)の生成が完了したときに、登録済みの受信エンドポイントへ送られます。 テスト送信では、架空のサンプルデータ(固定 UUID・架空の会社名/氏名/要約/BANT)を含む、本番と同一構造のペイロードが送られます。
| webhook-id required | string <uuid> Example: 7f3a2b10-9c4d-4e5f-8a6b-1d2e3f405162 配信 ID(delivery ID、UUID 形式)。署名対象であり、冪等化キーとしても使えます。 |
| webhook-timestamp required | string Example: 1768473960 署名時刻(Unix 秒、文字列)。リプレイ対策として現在時刻との差が ±5 分を超えるリクエストは拒否することを推奨します。 |
| webhook-signature required | string Example: v1,dUyj3KpeHdFdBKXTLKxyNtrfVSOPYojNEIjS0WaMbRw= リクエストの署名。 |
| event required | string 固定値 Value: "meeting.completed" |
| meetingId required | string <uuid> 商談 ID。 |
| tenantId required | string <uuid> テナント ID。 |
| scenarioId required | string <uuid> シナリオ ID。 |
required | object シナリオ情報。 |
object or null 商材情報。未紐付け時は | |
required | object 顧客情報。各フィールドは |
required | object 要約情報。 |
required | object 商談のメタ情報。 |
| occurredAt required | string <date-time> イベント発生日時(ISO 8601)。 |
{- "event": "meeting.completed",
- "meetingId": "00000000-0000-4000-8000-000000000001",
- "tenantId": "11111111-1111-4111-8111-111111111111",
- "scenarioId": "00000000-0000-4000-8000-000000000002",
- "scenario": {
- "id": "00000000-0000-4000-8000-000000000002",
- "title": "初回商談デモシナリオ"
}, - "product": {
- "name": "サンプル営業支援ツール"
}, - "customer": {
- "company": "株式会社サンプル商事",
- "name": "山田 太郎",
- "nameKana": "ヤマダ タロウ",
- "email": "yamada.taro@example.com",
- "prefecture": "東京都",
- "city": "千代田区"
}, - "summary": {
- "short": "業務効率化ツールの導入を前向きに検討中。次回は見積もりを提示する。",
- "detailed": "現行の営業管理が属人化しており、商談記録の自動化に強い関心を示された。導入時期は来期を想定。決裁は営業部長との合議制で、予算感は年額100万円程度まで。競合ツールとの比較資料を求められた。",
- "actionItems": [
- {
- "item": "見積もり書を作成して送付する",
- "assignee": "佐藤 花子",
- "dueDate": "2026-02-01"
}, - {
- "item": "競合ツールとの比較資料を共有する",
- "assignee": "佐藤 花子",
- "dueDate": "2026-01-25"
}
], - "bant": {
- "budget": "年額100万円程度",
- "authority": "営業部長との合議制",
- "needs": "商談記録の自動化・営業業務の効率化",
- "timeline": "来期(2026年4月)を想定"
}
}, - "meeting": {
- "startedAt": "2026-01-15T10:00:00.000Z",
- "endedAt": "2026-01-15T10:45:00.000Z",
- "entryLinkId": "00000000-0000-4000-8000-000000000003"
}, - "occurredAt": "2026-01-15T10:46:00.000Z"
}管理画面からの手動テスト送信のときのみ送られる、疎通確認用の軽量なペイロードです。 本番配信では送られません。
| webhook-id required | string <uuid> Example: 7f3a2b10-9c4d-4e5f-8a6b-1d2e3f405162 配信 ID(delivery ID、UUID 形式)。署名対象であり、冪等化キーとしても使えます。 |
| webhook-timestamp required | string Example: 1768473960 署名時刻(Unix 秒、文字列)。リプレイ対策として現在時刻との差が ±5 分を超えるリクエストは拒否することを推奨します。 |
| webhook-signature required | string Example: v1,dUyj3KpeHdFdBKXTLKxyNtrfVSOPYojNEIjS0WaMbRw= リクエストの署名。 |
| event required | string 固定値 Value: "test.ping" |
| tenantId required | string <uuid> テナント ID。 |
| message required | string 固定メッセージ |
| occurredAt required | string <date-time> イベント発生日時(ISO 8601)。 |
{- "event": "test.ping",
- "tenantId": "11111111-1111-4111-8111-111111111111",
- "message": "これはテスト送信です",
- "occurredAt": "2026-01-15T10:46:00.000Z"
}