フォーム ID

Webhook

署名付きの Webhook ペイロード、HMAC-SHA256 署名の検証、リトライのスケジュール、配信ログ。

Webhook は、受け付けた送信データを届いたそばからあなたのサーバーに送ります。配信は Standard Webhooks 方式で署名され、約 3 日間リトライされ、ダッシュボードに試行ごとに記録されます。すぐに使えるハンドラーは Webhook を受け取るにあります。

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

  1. ダッシュボードで Webhooks を開き、Add endpoint を選びます。
  2. HTTPS の URL を入力し、フォームを 1 つ、またはワークスペースのすべてのフォームを選びます。
  3. 署名シークレットをコピーします。whsec_ で始まり、全体が表示されるのは 1 回だけです。
  4. テストイベントを送って、ハンドラーを確認します。

エンドポイントの URL

  • https: のみ。デフォルトのポート 443 で、URL にユーザー名やパスワードを含めず、最大 2,048 文字。
  • 公開されたホスト名。IP アドレス、localhost、.local、.internal、.intranet、.lan、.home.arpa、.onion で終わる名前は拒否されます。ikiform.com、workers.dev、pages.dev も同様です。
  • ホスト名は公開アドレスだけに解決される必要があります。プライベート、ループバック、リンクローカル、キャリアグレード NAT の範囲は拒否されます。
  • URL は保存時と、毎回の配信の前にチェックされます。プライベートアドレスに解決されるようになったエンドポイントは無効化されます。
  • 1 つのワークスペースに登録できるエンドポイントは 3 件までです。Enterprise には上限がありません。

イベント

タイプ送信されるタイミングリトライ
submission.created送信データが受け付けられたとき、またはスパムの送信データがスパムではないとマークされたときあり
endpoint.testエンドポイントのページで Send test を選んだときなし(1 回のみ)

スパムで Webhook が送られることはありません。ワークスペースが月間の上限を超えて保留された送信データでも送られません。

リクエスト

各配信は JSON のボディと 3 つの署名ヘッダーを持つ POST で、Ikiform の配信サービスからユーザーエージェント Ikiform-Webhooks/1.0 で送られます。

ヘッダー
POST /webhooks/ikiform HTTP/1.1
content-type: application/json
user-agent: Ikiform-Webhooks/1.0
webhook-id: dlv_01k7v2d4n8r2p6s0w3y5b7c9e1
webhook-timestamp: 1792300000
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
ヘッダー値
webhook-id配信 ID。同じ配信のリトライでは毎回同じなので、重複の無視に使います
webhook-timestampこの試行に署名した時刻の Unix 秒。試行ごとに新しくなります
webhook-signaturev1, に base64 の HMAC-SHA256 を続けたもの。シークレットのローテーション中は、スペース区切りの複数の値になります

ペイロード

{
  "id": "dlv_01k7v2d4n8r2p6s0w3y5b7c9e1",
  "type": "submission.created",
  "timestamp": "2026-10-17T12:00:00.000Z",
  "api_version": "2026-10-17",
  "data": {
    "submission_id": "sub_01k7v2c9t3e8m5q4x6z0a1b2c3",
    "form": { "id": "frm_xxxxxxxxxxxxxxxx", "name": "Contact" },
    "fields": { "name": "Ada", "email": "ada@example.com", "message": "Hello" },
    "meta": {
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
      "origin": "https://example.com",
      "referrer": "https://example.com/contact",
      "country": "GB",
      "subject": null,
      "reply_to": "ada@example.com"
    },
    "created_at": "2026-10-17T12:00:00.000Z",
    "truncated": false
  }
}
フィールド説明
id配信 ID。webhook-id と同じ
typesubmission.created または endpoint.test
timestamp配信が作成された日時(ISO 8601、UTC)。リトライでも同じ
api_versionエンドポイントの作成時のペイロードのバージョン。現在は 2026-10-17
data.submission_id送信データの ID。REST API で取得できます
data.formフォームの id と name
data.fields保存された値。フィールドが定義されている場合は、バリデーションと型変換を経た値
data.metaREST API の meta と同じキー。すべてのキーが存在し、どの値も null になりえます。訪問者の IP やそのハッシュが送られることはありません
data.meta.user_agentブラウザーのユーザーエージェント。最大 512 文字
data.meta.origin, referrerブラウザーが送った場合の、送信元
data.meta.country2 文字の国コード。Cloudflare から取得
data.meta.subject, reply_to_subject と _replyto フィールドから
data.created_at送信データが保存された日時
data.truncatedボディが 256 KB を超える場合は true で、その場合 fields は空になります

meta の値はどれも null になりえます。フィールドの値は、自分のサーバーへのフォーム送信と同じく、信頼できない入力として扱ってください。

署名を検証する

Webhook 署名の計算方法
webhook-id.webhook-timestamp.生のボディ

HMAC-SHA256。鍵は whsec_ 以降を base64 デコードしたシークレット

webhook-signature: v1,base64(signature)

  • リクエストの生のボディを、受け取ったとおりに使ってください。JSON を解析して再シリアライズするとバイト列が変わります。
  • ヘッダーには、スペース区切りで複数の署名が入ることがあります。いずれかの v1 署名が一致すれば、リクエストを受け入れます。
  • 比較は定数時間で行い、現在時刻から 5 分以上ずれたタイムスタンプは拒否してください。

SDK を使う

verifyWebhook は上記のすべてを Web Crypto で行い、解析済みのイベントを返すか、reason 付きの WebhookVerificationError を投げます。Headers オブジェクトも、Node の req.headers のような単純なレコードも受け付けます。

app/api/webhooks/ikiform/route.ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";

export async function POST(request: Request) {
  const payload = await request.text();
  try {
    const event = await verifyWebhook({
      payload,
      headers: request.headers,
      secret: process.env.IKIFORM_WEBHOOK_SECRET!,
    });
    if (event.type === "submission.created") {
      console.log(event.data.fields);
    }
    return new Response(null, { status: 204 });
  } catch (error) {
    if (error instanceof WebhookVerificationError) {
      return new Response(error.reason, { status: 400 });
    }
    throw error;
  }
}

SDK を使わない

Standard Webhooks のどのライブラリでも動きます。手で書いても数行です:

import { createHmac, timingSafeEqual } from "node:crypto";

const secret = Buffer.from(process.env.IKIFORM_WEBHOOK_SECRET.replace(/^whsec_/, ""), "base64");

export function verify(body, headers) {
  const id = headers["webhook-id"];
  const timestamp = headers["webhook-timestamp"];
  const signatures = headers["webhook-signature"];
  if (!id || !timestamp || !signatures) return false;
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${id}.${timestamp}.${body}`).digest();
  return signatures.split(" ").some((entry) => {
    const [version, signature] = entry.split(",");
    if (version !== "v1" || !signature) return false;
    const received = Buffer.from(signature, "base64");
    return received.length === expected.length && timingSafeEqual(received, expected);
  });
}

署名の検証ツール

5 分の有効期間を無視する

ブラウザー内の Web Crypto で SDK の verifyWebhook を使います。貼り付けた内容がこのページの外に出ることはありません。

応答する

あなたの応答Ikiform の動作
15 秒以内の 2xx配信を成功として記録
410 Gone配信を失敗にし、エンドポイントをすぐに無効化
Retry-After 付きの 429 または 503その時間が経ってからリトライ。ただしスケジュールの次の段階より遅くはしない
リダイレクト従わず、失敗として扱う
その他のステータス、タイムアウト、ネットワークエラー下記のスケジュールでリトライ

時間のかかる処理は、キューなどを使って応答のあとに行ってください。レスポンスボディの先頭 4 KB が配信ログに保存されます。

リトライ

失敗した試行は、このスケジュールでリトライされます。各待ち時間には前後最大 20% のランダムなジッターが入ります。9 回目の試行(初回から約 3日6時間後)のあと、配信は失敗として記録されます。

Webhook のリトライスケジュール。各試行までの待ち時間を対数スケールで表示
試行待ち時間初回から
  1. 1すぐ0秒
  2. 25秒5秒
  3. 35分5分
  4. 430分35分
  5. 52時間2時間35分
  6. 65時間7時間35分
  7. 710時間17時間35分
  8. 81日1日18時間
  9. 91日12時間3日6時間

濃いバーは最短、薄いバーは最長の待ち時間で、前後 20% のジッターによるものです。9 回目の試行のあと、配信は失敗として記録されます。

無効化されたエンドポイント

エンドポイントへの配信が 5 日間すべて失敗すると、エンドポイントは無効化され、ワークスペースのオーナーにメールが届きます。410 Gone の応答や、送信先がプライベートになった場合はすぐに無効化されます。問題を直したら、エンドポイントのページから再びオンにしてください。

配信ログ

各エンドポイントのページには、配信がステータス付きで一覧表示されます。1 つを展開すると、すべての試行を確認できます。実行日時、自動・手動・テストのどれか、ステータスコード、所要時間、レスポンスの先頭 4 KB またはエラーです。そこからどの配信でもリトライできます。試行は 30 日間、配信は 90 日間保持されます。

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

Roll signing secret で新しいシークレットを作成します。その後 24 時間は、すべての配信が古いシークレットと新しいシークレットの両方で署名されるので、webhook-signature には 2 つの値が入り、イベントを取りこぼさずに新しいシークレットをデプロイできます。