Ringhum.

開発者

Webhook

通話終了、伝言受付、予約・注文・宿泊予約の変更、キャンペーン終了時に署名付きHTTPS通知を受け取り、それが本当にRinghumからのものかを検証する方法を説明します。

約2分で読めます 24 9月 2026更新

このページの内容

Webhookは、ワークスペースで何かが起きた瞬間に、あなたのサーバーにHTTPSリクエストを送信します。APIをポーリングする代わりにWebhookを使うと、通話が終了した際に要約、結果、収集された詳細情報、文字起こしをすぐに受け取れます。各配信には、あなたとRinghumだけが知る秘密鍵で署名が付けられるため、サーバー側でRinghum以外からのリクエストを拒否できます。

エンドポイントを追加する

エンドポイントの追加・テスト・削除ができるのは、ワークスペースのオーナー管理者のみです。

  1. サイドバーの開発者を開きます。
  2. Webhookカードでエンドポイントを追加をクリックします。
  3. エンドポイントURLを入力します。https://で始まる必要があります。
  4. イベントで、必要なイベントにチェックを入れます。call.endedはあらかじめチェックされています。
  5. エンドポイントを追加をクリックします。
  6. 緑色のボックスに表示された署名シークレット(whsec_で始まります)をコピーし、サーバーに保存します。完了をクリックします。

重要: 署名シークレットは一度だけ表示されます。紛失した場合は、エンドポイントを削除して再度追加し、新しいシークレットを取得してください。

エンドポイントは必要なだけ追加できます。Webhookはワークスペース内のすべてのアシスタントを対象とします。writeスコープを持つキーを使って、POST /webhooksでAPI経由でエンドポイントを管理することもできます。

イベント

イベント 送信タイミング
call.started アシスタントが通話に応答したとき
call.ended 通話が終了し要約されたとき(文字起こしと要約を含む)
call.transferred 通話が担当者に転送されたとき
message.taken アシスタントが伝言を受け付けたとき
appointment.booked アシスタントが予約を入れたとき
appointment.rescheduled 予約の日時が変更されたとき
appointment.cancelled 予約がキャンセルされたとき
order.created 注文が行われたとき(アシスタント、手動、API経由いずれも)
order.updated 注文のステータスが変わったとき
order.cancelled 注文がキャンセルされたとき
reservation.created 部屋が予約されたとき(アシスタント、手動、API経由いずれも)
reservation.updated 予約のステータスが変わったとき(確定、チェックイン、チェックアウト、無断キャンセル)
reservation.cancelled 予約がキャンセルされたとき
campaign.completed 発信キャンペーンがリストへの発信を終えたとき
test.ping テストを送信をクリックしたとき

配信内容の例

各配信は、JSON本文と以下のヘッダーを持つPOSTリクエストです。

POST https://example.com/hooks/ringhum
Content-Type: application/json
User-Agent: Ringhum-Webhooks/1.0
X-Ringhum-Event: call.ended
X-Ringhum-Timestamp: 1789250000
X-Ringhum-Signature: v1=5f1a…

{
  "id": "evt_8f2k…",
  "type": "call.ended",
  "created_at": "2026-09-24T14:03:11+00:00",
  "data": {
    "call_id": 4812,
    "direction": "inbound",
    "from": "+14155550132",
    "to": "+14155550100",
    "assistant_id": 3,
    "status": "completed",
    "outcome": "message_taken",
    "sentiment": "neutral",
    "duration_seconds": 94,
    "summary": "Caller asked for a quote for a kitchen repair…",
    "extracted": { "name": "Dana Lee", "reason": "Quote" },
    "transcript": [
      { "role": "assistant", "content": "Hello, you've reached…" },
      { "role": "user", "content": "Hi, I'd like a quote…" }
    ]
  }
}

dataオブジェクトの内容はイベントによって異なります。

  • call.endedmessage.taken:上記の通話項目。
  • call.startedcall.transferred:call_iddirectionfromtoassistant_idstatusstarted_at
  • appointment.*:appointment_idtitlestatusstarts_atends_attimezonecustomer(名前、電話番号、メール)、contact_idservicestaffcall_idnotes
  • order.*:order_idnumberstatusfulfillmentcustomeraddress、オプションと価格を含むitemscurrencysubtotalfeetotalsourcecall_id、キャンセルの場合はcancel_reason
  • reservation.*:reservation_idnumberstatusroomcheck_incheck_outnightsadultschildrenguestcurrencynightlytotalsource
  • campaign.completed:campaign_idname、キャンペーンの進捗件数。

注: 通話中にアシスタントが予約を取った場合、appointment.bookedが2回届くことがあります。1回目は予約成立時に予約項目とともに、2回目は通話の要約後に通話項目とともに送信されます。dataappointment_idcall_idのどちらが含まれているかを確認し、idフィールドを使って二重処理を避けてください。

署名を検証する

署名は、タイムスタンプ、ドット、リクエスト本文の生データを、エンドポイントの署名シークレットで鍵付けしたHMAC-SHA256です。v1=に続けて16進ダイジェストの形で送信されます。

  1. JSONとしてパースする前の、受信した通りの生の本文を読み取ります。
  2. {X-Ringhum-Timestamp}.{生の本文}という文字列を組み立てます。
  3. シークレットでHMAC-SHA256を計算し、先頭にv1=を付けます。
  4. 定数時間比較を使ってX-Ringhum-Signatureと照合します。
  5. リプレイ攻撃を防ぐため、タイムスタンプが5分以上前の場合はリクエストを拒否します。

Node.js:

const crypto = require('crypto');

function isValid(req, rawBody, secret) {
  const ts = req.header('X-Ringhum-Timestamp');
  const sig = req.header('X-Ringhum-Signature') || '';
  const expected = 'v1=' + crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && sig.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

PHP:

$ts = $_SERVER['HTTP_X_RINGHUM_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_RINGHUM_SIGNATURE'] ?? '';
$expected = 'v1=' . hash_hmac('sha256', $ts . '.' . file_get_contents('php://input'), $secret);
if (! hash_equals($expected, $sig) || abs(time() - (int) $ts) > 300) {
    http_response_code(400);
    exit;
}

レスポンス、タイムアウト、再試行

  • 配信を確認するには、2xxのいずれかのステータスで応答してください。時間のかかる処理は、応答した後に行ってください。
  • Ringhumは、応答を最大10秒間待ちます。
  • エンドポイントが2xxで応答しない場合、配信は合計最大3回試行されます:即座に1回、約10秒後にもう1回、約60秒後に最後の1回です。その後は破棄されます。
  • 配信は順序どおりに届かないことがあります。created_atdata内のIDを使って順序を並べ替えてください。

Webhookの表には、各エンドポイントの最終HTTPステータスと送信日時が表示されます。失敗したエンドポイントもそのまま有効な状態が続きます。Ringhumが自動でオフにすることはありません。

テスト、一時停止、削除

  • テストを送信test.pingイベントを即座に送信し、エンドポイントから返されたHTTPステータスがメッセージで表示されます。
  • 有効スイッチでエンドポイントを一時停止できます。オフの間に発生したイベントは、後から送信されることはありません。
  • 削除で、エンドポイントとそのシークレットが削除されます。

よくある質問

連携ページのZapier、Make、n8nとの違いは何ですか? それらの連携は、連携ページとその6種類のイベントを使用します。本文は{"event", "workspace", "sent_at", "data"}の形式で、シークレットを設定した場合の署名ヘッダーはX-Ringhum-Signature: sha256=…という、本文のみのHMAC-SHA256です。ここで説明している開発者向けWebhookは、より多くのイベントをカバーし、タイムスタンプ付きのv1=署名を使用します。詳しくは送信する内容を選ぶをご覧ください。

エンドポイントは2xxを返しているのに、コード側で何も受信できません。 そのエンドポイントでイベントにチェックが入っているか、エンドポイントが有効になっているか、ファイアウォールがインターネットからのリクエストを許可しているかを確認してください。

署名の検証が失敗するのはなぜですか? 多くの場合、ハッシュ計算の前に本文がパースされ、再エンコードされていることが原因です。受信した生のバイト列をそのままハッシュ化してください。

解決しませんか?

[email protected]までメールするか、メッセージを送る。TeamプランとScaleプランは優先サポートを受けられます。

サポートに問い合わせる