ゴリラセールス Webhook 連携ガイド (1.0.0)

Download OpenAPI specification:

このガイドは、ゴリラセールスの Webhook を受信するエンドポイントを実装する開発者向けの資料です。 商談完了などのイベントが発生すると、あらかじめ登録した受信 URL へ、署名付きの HTTP POST リクエストが届きます。 この資料だけで、受信エンドポイントの実装・署名検証・動作確認まで完結できるよう構成しています。

署名方式は Standard Webhooks 準拠です。 Standard Webhooks に対応した検証ライブラリを利用して署名を検証することもできますし、後述のコード例のように自前で検証することもできます。

はじめに / 概要

商談が完了すると、ゴリラセールスは商談データ・要約・BANT 情報をまとめたイベント(meeting.completed)を、 登録済みの受信 URL へ署名付き POST で通知します。受信側はこの通知を受け取り、自社の CRM やデータ基盤へ連携できます。

  • 通知は HTTPS の受信エンドポイント URL に対して送られます。
  • 各エンドポイントには固有の signing secretwhsec_...)が発行され、受信側はこれを使ってリクエストの署名を検証します。
  • 署名方式は Standard Webhooks 準拠です。準拠ライブラリでの検証も、自前実装での検証も可能です。
  • 日時はすべて UTC の ISO 8601 文字列(例: 2026-01-15T10:00:00.000Z)で送られます。

通知される具体的なペイロード構造は、本ページ下部の Webhooks セクション(meeting.completed / test.ping)を参照してください。

セットアップ手順

受信を始めるには、管理画面から受信エンドポイントを登録します。

エンドポイントの登録

  1. 管理画面の 「組織設定 > Webhook 連携」 を開きます。
  2. 受信する URL を登録します。
    • URL は HTTPS のドメインのみ登録できます(IP アドレス・localhost は登録できません)。
    • 1 つの組織につき 最大 5 件まで登録できます。
    • 同一 URL の重複登録はできません。
  3. 登録すると、そのエンドポイント固有の signing secretwhsec_...)が発行されます。

signing secret の保管

signing secret(whsec_...)は、受信したリクエストが本当にゴリラセールスから送られたものかを検証するための鍵です。

  • 安全に保管してください。 環境変数やシークレットマネージャーに格納し、ソースコードやログに直書きしないでください。
  • 漏洩が疑われる場合は、管理画面から secret を再生成できます。再生成すると古い secret では検証できなくなるため、受信側の secret も差し替えてください。

テスト送信で疎通確認する

「組織設定 > Webhook 連携」の各エンドポイント行の 「テスト送信」 から、実際に受信できるかを確認できます。 送信するイベント種別は 2 種類から選べます。

  • 疎通確認(test.ping — 軽量な疎通確認用のペイロード。まず受信できること・2xx を返せることの確認に使います。
  • サンプルデータ(meeting.completed — 架空のダミーデータ(固定 UUID・架空の会社名/氏名/要約/BANT/アクションアイテム)を含む、本番と同一構造meeting.completed ペイロード。受信側のパース・マッピング実装を本番前に検証できます。

補足:

  • 無効化されたエンドポイントにはテスト送信できません。
  • テスト送信も本番と同じ signing secret で署名されるため、署名検証の実装をそのまま試せます。
  • テスト送信の結果は、管理画面の配信ログに記録されます。

イベント種別

通知されるイベントは次の 2 種類です。ペイロードの詳細スキーマは本ページ下部の Webhooks セクションを参照してください。

イベント値 説明 発火契機
meeting.completed 商談完了 商談が完了し、要約(サマリー)の生成が完了したとき。テスト送信では架空のサンプルデータで送られます。
test.ping 疎通確認 管理画面からの手動テスト送信のときのみ。本番配信では送られません。

すべてのペイロードは JSON オブジェクトで、トップレベルに event(イベント種別文字列)・tenantIdoccurredAt を含みます。

受信ヘッダと署名検証

各リクエストには、Content-Type(application/json)に加えて、以下の署名関連ヘッダが付与されます。

ヘッダ名 内容
webhook-id 配信 ID(delivery ID)。署名対象であり、冪等化キーとしても使えます。
webhook-timestamp 署名時刻(Unix 秒、文字列)。
webhook-signature v1,<base64 署名> 形式(スペースなし)。複数の署名がスペース区切りで入る場合があります。

signing secret の形式

signing secret は whsec_ プレフィックス + base64 文字列です(例: whsec_MfKQ9r8...)。

署名アルゴリズム

受信側は、登録時に発行された signing secret を使い、以下の手順で HMAC を再計算して署名の一致を確認します。

  1. 署名対象文字列をピリオド区切りで組み立てます。

    {webhook-id}.{webhook-timestamp}.{リクエストボディ生文字列}
    

    ボディは受信した生の JSON 文字列をそのまま使います(再シリアライズしないでください)。

  2. signing secret から whsec_ プレフィックスを外し、残りを base64 デコードしたバイト列を HMAC 鍵にします。

  3. 鍵で署名対象文字列を HMAC-SHA256 し、結果を base64 エンコードします。

  4. 受信した webhook-signaturev1,<署名> 形式)から、バージョン接頭辞 v1, を外した署名と、手順 3 の結果を定数時間比較します。

タイムスタンプ許容範囲(リプレイ対策)

署名時刻は webhook-timestamp(Unix 秒)に載っています。リプレイ攻撃を防ぐため、 Standard Webhooks の推奨に従い、現在時刻との差が概ね ±5 分(300 秒)を超えるリクエストは拒否することを推奨します。

検証コード例(Node.js / TypeScript)

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);
  });
}

受信後にやるべき処理(ベストプラクティス)

  • まず 2xx を速やかに返す。 成功判定は HTTP 2xx です。受信後の重い処理(DB 書き込み・外部連携など)は非同期に回し、 まず 2xx を返してください。応答が 10 秒を超えるとタイムアウト扱いになり、リトライされます。
  • 署名を必ず検証する。 受信したら署名検証を行い、検証に失敗したリクエストは拒否してください。 ボディはパース前の生文字列で検証します。
  • webhook-id で冪等化する。 リトライにより、同一の配信が複数回届くことがあります。 webhook-id(配信 ID)を冪等化キーに使い、二重処理を防いでください。
  • 送信元 IP は固定されていません。 送信元 IP アドレスによる許可リスト制御は想定していません。 認証は署名検証で行ってください。
  • 未知フィールド・null に耐える。 フィールドの追加や null 値がありえます。 未知のキーは無視し、null 許容フィールドは存在を前提にせず扱ってください。

配信・リトライ仕様

本番配信(<code>meeting.completed</code>)

配信・リトライ仕様

本番配信(meeting.completed

  • 成功判定は HTTP 2xx です。
  • 失敗時は最大 5 回試行し、指数バックオフで再送します(初回失敗から 30 秒 → 60 秒 → 120 秒 → 240 秒)。
  • リトライ判定:
    • 2xx → 成功で確定。
    • 恒久 4xx408 / 429 を除く 4xx) → 失敗で確定し、リトライしません
    • 5xx / 408 / 429 / ネットワークエラー / タイムアウト(10 秒) → リトライ対象。最大試行に達したら失敗で確定します。
  • リダイレクト(3xx)は追従しません(失敗扱い)。受信 URL は最終的な URL を登録してください。
  • 再送されるボディは初回と同一です(試行間で内容は変わりません)。

テスト送信

  • 管理画面からのテスト送信は、同期的に 1 回だけ送信します(自動リトライはありません)。
  • 結果は本番配信と同じ配信ログに記録されます。

配信ログ・再送

管理画面の配信ログで、各配信の成否・イベント種別・応答内容を確認できます。 失敗した配信は、管理画面から手動で再送できます。

FAQ / トラブルシュート

Q. 通知が届きません。

  • 受信エンドポイントが無効化されていないかを、管理画面「組織設定 > Webhook 連携」で確認してください。無効化されたエンドポイントには配信されません。
  • 管理画面の配信ログで、配信が試行されているか・どの応答(ステータスコード)が返っているかを確認してください。
  • まず テスト送信(test.ping で疎通を確認し、受信側が 2xx を返せているかを切り分けてください。
  • 受信 URL がリダイレクト(3xx)を返していないか確認してください。リダイレクトは追従されません。

Q. 署名検証に失敗します。

  • 検証にはパース前の生のリクエストボディを使っているか確認してください。JSON を再シリアライズすると署名が一致しません。
  • signing secret を再生成した場合、受信側の secret も新しいものに差し替える必要があります。古い secret では検証に失敗します。
  • webhook-timestamp の許容範囲(±5 分)でリクエストが拒否されていないか、サーバーの時刻同期(NTP)を確認してください。

Q. 同じ商談の通知が複数回届きました。

  • リトライや再送により、同一の配信が複数回届くことがあります。webhook-id を冪等化キーに使い、二重処理を防いでください。

商談完了イベント Webhook

商談が完了し、要約(サマリー)の生成が完了したときに、登録済みの受信エンドポイントへ送られます。 テスト送信では、架空のサンプルデータ(固定 UUID・架空の会社名/氏名/要約/BANT)を含む、本番と同一構造のペイロードが送られます。

Authorizations:
WebhookSignature
header Parameters
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=

リクエストの署名。v1,<base64 署名> 形式(スペースなし)で、複数の署名が スペース区切りで入る場合があります。検証手順は「受信ヘッダと署名検証」を参照してください。

Request Body schema: application/json
required
event
required
string

固定値 "meeting.completed"

Value: "meeting.completed"
meetingId
required
string <uuid>

商談 ID。

tenantId
required
string <uuid>

テナント ID。

scenarioId
required
string <uuid>

シナリオ ID。

required
object

シナリオ情報。

object or null

商材情報。未紐付け時は null

required
object

顧客情報。各フィールドは null になりえます。

required
object

要約情報。

required
object

商談のメタ情報。

occurredAt
required
string <date-time>

イベント発生日時(ISO 8601)。

Responses

Request samples

Content type
application/json
{
  • "event": "meeting.completed",
  • "meetingId": "00000000-0000-4000-8000-000000000001",
  • "tenantId": "11111111-1111-4111-8111-111111111111",
  • "scenarioId": "00000000-0000-4000-8000-000000000002",
  • "scenario": {
    },
  • "product": {
    },
  • "customer": {
    },
  • "summary": {
    },
  • "meeting": {
    },
  • "occurredAt": "2026-01-15T10:46:00.000Z"
}

疎通確認イベント Webhook

管理画面からの手動テスト送信のときのみ送られる、疎通確認用の軽量なペイロードです。 本番配信では送られません。

Authorizations:
WebhookSignature
header Parameters
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=

リクエストの署名。v1,<base64 署名> 形式(スペースなし)で、複数の署名が スペース区切りで入る場合があります。検証手順は「受信ヘッダと署名検証」を参照してください。

Request Body schema: application/json
required
event
required
string

固定値 "test.ping"

Value: "test.ping"
tenantId
required
string <uuid>

テナント ID。

message
required
string

固定メッセージ "これはテスト送信です"

occurredAt
required
string <date-time>

イベント発生日時(ISO 8601)。

Responses

Request samples

Content type
application/json
{
  • "event": "test.ping",
  • "tenantId": "11111111-1111-4111-8111-111111111111",
  • "message": "これはテスト送信です",
  • "occurredAt": "2026-01-15T10:46:00.000Z"
}