Webhook(JSON)
Webhook のルールは、一致した各回答を JSON として指定の URL に POST します。CRM、表計算ツール、独自のサーバー、または Zapier、Make、n8n などの自動化プラットフォームへのデータ連携に使えます。
Webhook のルールを作成する
- + 新しいルールをクリックして Webhook を選びます
- 条件ステップ:毎回の回答のままにするか、承認後のみ / 却下時を選んで承認者を設定します。一致する回答だけを送るには条件を追加します
- 宛先ステップ:エンドポイントの URL を貼り付けます(HTTPS のみ)。メッセージのステップはありません:ルールは固定の JSON ペイロードを送信します。URL の下のペイロードを表示で、フォームの質問を含む内容を確認してコピーできます
- ルールを作成をクリックし、一度だけ表示される署名シークレットをコピーします(下記参照)

テスト送信は、署名付きのサンプルペイロードをエンドポイントに送り、返された HTTP ステータスを表示します。保存された URL は暗号化して保存され、マスクして表示されます。新しい URL を貼り付けるには置き換えをクリックします。
ペイロード
各リクエストは POST、Content-Type: application/json で、本文は次のとおりです:
{
"version": 1,
"event": "submitted",
"form": { "id": "1AbC...", "name": "Workshop sign-up" },
"response": {
"id": "a3f1...",
"submittedAt": "2026-01-31T09:30:00.000Z",
"respondentEmail": "respondent@example.com",
"answers": [
{ "questionId": "q1", "title": "Your name", "value": "Ada Lovelace" },
{ "questionId": "q3", "title": "Department", "value": "Ops" }
]
},
"rule": { "id": "rule id", "name": "Zapier: new lead" }
}
eventはsubmitted、approved、rejectedのいずれかで、X-Skyfield-Eventヘッダーにも含まれますresponse.respondentEmailは、フォームがメールアドレスを収集していない限りnullですanswers[].valueは常に文字列で、チェックボックスの回答は,で結合されますrule.idとrule.nameは実行されたルールを示します。ルールに名前がない場合、nameはnullですapprovedとrejectedのときは、approval: { "decision": "approved", "decidedBy": "Dana" }が追加されます。decidedByは承認者が承認ページで入力した名前です。入力がない場合は承認者のメールアドレス、それもなければnullです
上記の形が安定している限り、version は 1 のままです。フィールドが追加されることはありますが、バージョンを上げずに削除や改名が行われることはありません。
署名を検証する
すべてのリクエストには X-Skyfield-Signature ヘッダーが付きます。値は sha256=<hex> で、ルールの署名シークレットを鍵としたリクエスト本文(生データ)の HMAC-SHA256 です。リクエストを信頼する前に検証してください。

シークレット(whsec_...)は、ルールに初めて Webhook URL を設定して保存した直後に一度だけ表示されます。そのときにコピーしてください。再表示はできません。後で URL を置き換えても、シークレットは変わりません。紛失した場合は、ルールを開いて新しい署名シークレットをクリックし、保存します。新しいシークレットが一度だけ表示され、古いものは直ちに無効になります。
HMAC は受信した本文のバイト列そのものに対して計算してください。先に JSON をパースして再シリアライズすると空白が変わり、比較が失敗します。
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto'
// rawBody: string or Buffer of the request body, before any JSON parsing
function verify(rawBody, header, secret) {
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(header ?? '')
return a.length === b.length && timingSafeEqual(a, b)
}
// Express example: use express.raw() so req.body is the untouched bytes
app.post('/hook', express.raw({ type: 'application/json' }), (req, res) => {
if (!verify(req.body, req.get('X-Skyfield-Signature'), process.env.SKYFIELD_SECRET))
return res.status(401).end()
const payload = JSON.parse(req.body)
res.status(200).end()
})
Python
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
digest = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest("sha256=" + digest, header or "")
# Flask example
@app.post("/hook")
def hook():
if not verify(request.get_data(), request.headers.get("X-Skyfield-Signature"), SECRET):
return "", 401
payload = request.get_json()
return "", 200
任意の 2xx ステータスで応答してください。本文は無視されます。
Zapier、Make、n8n
3つとも汎用の JSON Webhook を受け付けます:
- Zapier:トリガー Webhooks by Zapier、イベント Catch Hook(署名を自分で検証する場合は Catch Raw Hook)。Zapier が表示する URL をルールに貼り付けます
- Make:Webhooks モジュールの Custom webhook を追加し、その URL をコピーします
- n8n:Webhook ノードを追加し、メソッドを POST にして、本番用 URL を使います
ルールからテストを送信し、プラットフォーム側で response.answers のフィールドをマッピングします。サンプルペイロードはプレースホルダーの回答を使うため、すべてのフィールドが揃っています。
配信と制限
- エンドポイントは、公開インターネット上で HTTPS により到達できる必要があります。プライベートアドレスやローカルアドレスは保存時に拒否されます
- リダイレクトは追跡されません。最終的な URL を使ってください
- エンドポイントの応答待ち時間は 5 秒です。タイムアウトや 5xx 応答は 1 回再試行されます
- 404 または 410 の応答は、エンドポイントが存在しないことを意味します。ルールは一時停止し、メールが 1 通届きます。ルールに新しい URL を貼り付けると再開します
- 履歴ページには、各配信とエンドポイントが返した HTTP ステータスが一覧表示されます
- 一時停止中またはオフの Webhook のルールが、フォームの他のルールを妨げることはありません
知っておきたいこと
- Webhook のルールは送信タイミングに従うため、エンドポイントはすべての送信の代わりに承認の判断を受け取ることもできます。送信タイミングを参照してください
- 確認済みの回答だけを送るには、ルールの送信タイミングを承認後のみにして承認者を選びます。承認を参照してください。ペイロードには
approval.decisionが含まれます - チャンネルを変更… で Webhook のルールをメールやチャットチャンネルに移せます。新しい送り先はそこで設定します。Webhook に戻す場合は URL をもう一度貼り付ける必要があります
- Webhook のルールには有効なライセンスが必要です。無料トライアルも対象です。ライセンスが必要な機能を参照してください
