コンテンツにスキップ

Webhook

Bona Fide は、サブスクライブしたエンベロープのイベントごとに、エンドポイントへ HTTPS の POST を送信します。配信は Standard Webhooks 仕様に従っているため、その仕様のどのライブラリでも検証できます。

設定 › Webhook で登録するか、org:manage スコープを持つ API キーを使って登録します。

ターミナルウィンドウ
curl https://api.bonafidesign.com/v1/webhook-endpoints \
-H "Authorization: Bearer $BONA_FIDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/hooks/bona-fide",
"description": "Production",
"events": ["envelope.completed", "envelope.sealed", "envelope.declined"]
}'

レスポンスには secret(whsec_…)が含まれますが、このとき一度だけです。events を空のリストにすると、すべてのイベントをサブスクライブします。 URL は公開された https:// である必要があります。エンドポイントは 1 つのモードに属します。テストキーで作成したエンドポイントは テストモードのエンベロープのイベントだけを、本番のエンドポイントは本番のイベントだけを受信します。

PATCH /v1/webhook-endpoints/{id} は、URL、イベント、説明を変更し、エンドポイントを一時停止または再開します (enabled)。POST /v1/webhook-endpoints/{id}/test は webhook.test の ping を送信します。

タイプ タイミング
envelope.created エンベロープが作成された
envelope.ready ドキュメントがレンダリングされ、エンベロープが受信者に向けて準備できた
recipient.sent 受信者の順番になった(メール配信の場合は、その受信者にリンクが送信された)
recipient.viewed 受信者が初めて署名ページを開いた
recipient.signed 受信者が送信した(または自動的に副署された)
recipient.declined 受信者が辞退した
envelope.completed すべての受信者が完了した。data.values に変数と入力されたすべての値が含まれる
envelope.sealed 封印済み PDF をダウンロードできるようになった
envelope.declined 受信者が辞退したため、エンベロープが終了した
envelope.voided エンベロープを無効化した
envelope.expired 完了前に expiresAt を過ぎた
signing_link.used 訪問者が常設署名リンクからエンベロープを開始した

acceptance.created はスキーマで予約されていますが、まだ発行されません。

{
"id": "evt_9sKq2Lm4Tz",
"type": "envelope.completed",
"createdAt": "2026-10-13T14:09:52.004Z",
"testMode": false,
"data": {
"envelope": {
"id": "env_8Gm2kQ4rT1",
"status": "completed",
"seal": "pending",
"recipients": [{ "id": "rcp_5Jw0pLs9Xe", "role": "client", "status": "completed", "…": "…" }],
"externalId": "user_8841",
"metadata": {},
"…": "…"
},
"values": {
"variables": { "client": { "name": "Acme Robotics, Inc." }, "effective_date": "2026-10-13" },
"recipients": {
"client": { "client_title": "CEO", "start_date": "2026-11-01" }
}
}
}
}

data.envelope は、イベント発生時点の完全なエンベロープです。data.values は envelope.completed にのみ含まれ、送信した変数と、各ロールのフィールドの値(フィールド ID ごと)が格納されます。

各配信には次のヘッダーが含まれます。

ヘッダー 値
webhook-id イベント ID(evt_…)。リトライ時も同じです。重複排除に使用します
webhook-timestamp この試行に署名した時刻(Unix 秒)
webhook-signature v1,<base64 HMAC-SHA256>。複数のシークレットで署名する場合はスペース区切り
user-agent BonaFide-Webhooks/1

署名は {webhook-id}.{webhook-timestamp}.{raw body} に対する HMAC-SHA256 で、キーにはシークレットの whsec_ 以降の部分を base64 デコードしたものを使います。(JSON として解析する前の)生の本文を検証し、定数時間で比較して、 自分の時計と 5 分以上ずれているタイムスタンプは拒否してください。

import express from 'express';
import { Webhook } from 'standardwebhooks'; // npm i standardwebhooks
const wh = new Webhook(process.env.BONA_FIDE_WEBHOOK_SECRET!); // whsec_…
const app = express();
app.post('/hooks/bona-fide', express.raw({ type: 'application/json' }), (req, res) => {
let event;
try {
event = wh.verify(req.body, req.headers as Record<string, string>); // throws if forged or too old
} catch {
return res.sendStatus(400);
}
queue.add(event); // do the work asynchronously and answer quickly
res.sendStatus(204);
});

10 秒以内に 2xx が返されれば、配信は成功です。リダイレクトはたどりません。それ以外の場合は、バックオフを伴ってリトライされます。 リトライは 5 秒後、5 分後、30 分後、2 時間後、5 時間後、10 時間後、14 時間後、20 時間後、24 時間後に行われ、 イベントの発生から最大 3 日間続きます。その後、配信は失敗として記録されます。

  • すばやく応答し、処理は非同期で行ってください。重複排除には webhook-id を使います。
  • 配信は順不同で届くことがあります。順序を前提にせず、data.envelope.status を確認してください。
  • GET /v1/webhook-endpoints/{id}/deliveries は、最近の試行をステータスコード、エラー、所要時間とともに一覧表示します。 また、各エンドポイントには 24 時間の成功率(health)が表示されます。
  • POST /v1/events/{id}/redeliver は、たとえば障害の後などに、イベントをエンドポイントへ再送します。

シークレットのローテーション

Section titled “シークレットのローテーション”

POST /v1/webhook-endpoints/{id}/secret/rotate は、新しいシークレットを直ちに返します。その後 24 時間は、すべての 配信が新旧両方のシークレットで署名されるため(webhook-signature に 2 つのエントリー)、イベントを取りこぼすことなく 新しいシークレットをデプロイできます。