本文へ移動
Siteon
目次 Webhook

Docs

Webhook

届いたお問い合わせを1件ごとに、署名付きの JSON で Zapier・Make・CRM・自社のサーバーへ送る(有料プラン・1サイト5本)。送る形・署名の検証・冪等性・再送・送り先の制限・テスト送信。

Siteon は、AI で作ったサイトのためのインフラです。AI や手で作った静的サイト(HTML)に、ホスティング・お客さん(お店の人)が直せる CMS・お問い合わせフォーム・アクセス解析・AI エージェントからの操作(CLI・MCP)を足し、そのまま納品できる状態にします。

できること

フォームでお問い合わせを受け付けるたびに、登録した URL へ署名付きの JSON を POST します。Zapier や Make の「Webhook で受け取る」トリガー、CRM の受け口、自社のサーバーなどにつなげられます。

項目内容
プラン有料プラン(Lite・Standard・Business)だけ。Free プラン では使えません(契約が切れて Free と同じ扱いになったサイトも送りません)
本数1サイト5本まで。送るフォームを選べます(選ばなければ全フォーム)
送り先https:// の URL だけ(送り先の制限)
成功10秒以内に 2xx が返ること
再送失敗したら 2・4・8・16・32・60・60分おきに送り直し、計8回で「失敗」(およそ3時間)
操作管理画面の「設定 → 詳細 → Webhook」、CLI の siteon webhooks、MCP の webhooks_*(CLI・MCP・API キー)

追加・削除・テスト送信ができるのはサイトのオーナーだけです(スタッフは一覧を見るだけ)。お店へのメールや Slack の通知とは別に動き、Webhook が失敗してもお問い合わせは消えません。

追加する

管理画面の「設定 → 詳細 → Webhook」で送り先の URL と対象のフォームを選んで追加します。CLI なら:

siteon webhooks add https://hooks.example.com/siteon --site hanaya --form contact

署名用の秘密(whsec_ で始まる文字列)は、追加したときに1回だけ表示されます。 受け取り側の環境変数などに保存してください。あとから見ることはできません。漏れたり失くしたりしたら、その Webhook を消して作り直します(新しい秘密が出ます)。

送る JSON

POST <登録した URL>、content-type: application/json で次を送ります。

{
  "event": "form.submitted",
  "site": "hanaya",
  "form": "contact",
  "submission_id": "…",
  "submitted_at": "2026-10-04T09:30:00.000Z",
  "data": { "name": "山田 花子", "email": "[email protected]", "message": "秋の花束を予約したいです" },
  "attribution": {
    "first": { "utm_source": "google", "utm_medium": "cpc", "gclid": "…", "landing": "/", "referrer": "…", "at": "…" },
    "last": { "utm_source": "instagram", "landing": "/menu/", "at": "…" }
  },
  "test": false
}
キー中身
eventform.submitted(テスト送信は webhook.test)
site / formサイト ID / フォームのキー
submission_id受付 ID。管理画面の一覧と同じ ID
submitted_at受け付けた日時(ISO 8601・UTC)
data入力内容(schema.json の fields[].key ごと)
attribution流入元。first(最初に来たとき)と last(最後に来たとき)に utm_*・gclid・fbclid・着地ページ・参照元(流入元の記録)
testテスト送信なら true

ヘッダ:

ヘッダ中身
X-SiteKit-Signaturet=<UNIX 秒>,v1=<署名>。署名は HMAC-SHA256(秘密, t + "." + 本文) の16進
Idempotency-Key受付 ID(submission_id と同じ)。再送でも変わりません
X-SiteKit-Eventevent と同じ値
X-SiteKit-Delivery送信ごとの ID(調べるとき用)

署名を確かめる

署名の形は Stripe の Webhook と同じです。受け取り側で次を確かめます。

  1. ヘッダから t と v1 を取り出す
  2. t + "." + 受け取った本文(そのままの文字列) を秘密で HMAC-SHA256 し、16進にしたものが v1 と一致する(比べるときは時間が一定の比較を使う)
  3. t が今から5分以上ずれていたら拒否する(古い送信の使い回しを防ぐ)

本文は JSON として読み直す前の文字列で計算します。 読み直してから文字列に戻すと、空白や並びが変わって一致しません。

Node.js:

import crypto from "node:crypto";

// rawBody: 受け取ったままの本文(文字列)、header: X-SiteKit-Signature の値
export function verify(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 ?? "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Python:

import hashlib, hmac, time

def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t = int(parts.get("t", "0"))
    if not t or abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

秘密は whsec_ を含めた文字列全体をそのまま鍵にします。

冪等性(同じ問い合わせが2回届いたとき)

応答が途中で切れた場合などに、同じお問い合わせが2回以上届くことがあります。Idempotency-Key(=submission_id)は再送でも同じなので、受け取り側で一度処理した ID は読み飛ばして 2xx を返してください。CRM に二重に登録されるのを防げます。

再送と失敗

  • 受け付けた直後に1回目を送ります。失敗(2xx 以外・10秒を超えた・つながらない)したら、2・4・8・16・32・60・60分おきに送り直し、計8回で「失敗」として止めます
  • リダイレクト(3xx)は追わず、失敗として扱います。 登録する URL はリダイレクトしない最終の URL にします
  • 応答の本文は読みません。2xx を返すまでの時間を短くしたいときは、受け取り側でキューに積んでからすぐ 2xx を返します
  • 送るたびに保存済みのお問い合わせから組み立てるので、再送の前にお問い合わせを消すと、その分はもう送りません
  • 直近の送信結果は、管理画面の「設定 → 詳細 → Webhook」と siteon webhooks list で見られます

送り先の制限

送り先は、追加するときと送るたびに確かめます。次のものは登録できず、送りません。

  • https:// 以外(http:// など)。ポートの指定(既定の 443 以外)。user:pass@ を含む URL
  • IP アドレスの直書き(公開の IP も不可)
  • ドットの無い名前・localhost・.local・.internal・.home.arpa・.test・.example・.invalid などの内部向け・予約済みの名前
  • Siteon 自身のホスト(API・管理画面・ホスティングの共通ドメインとそのサブドメイン)

社内のサーバーに送るときは、インターネットから https で届く公開の名前を用意してください。

テスト送信

管理画面の「設定 → 詳細 → Webhook」のテスト送信か、siteon webhooks test <id>(MCP の webhooks_test)で、保存済みの URL へ本物の秘密で署名したダミーを送り、結果(HTTP ステータス)を返します。

  • event は webhook.test、test は true、submission_id は test_ で始まります。data は対象フォームの項目に合わせたダミー、attribution は空です
  • お問い合わせとしては保存されず、件数にも数えません
  • 1本につき1分に1回まで(サイトの1日のテスト送信の枠にも数えます)

受け取り側では、test が true のものは署名だけ確かめて、本番の処理(CRM への登録など)はしないようにしておくと安全です。

API キーの権限

CLI・MCP から操作するときの鍵の権限です(CLI・MCP・API キー)。

操作要る scope
一覧(webhooks list / webhooks_list)sites:read
追加(webhooks add / webhooks_add)sites:write と submissions:read の両方(入力内容を外に送れるようになるため)
削除(webhooks remove / webhooks_remove)sites:write
テスト送信(webhooks test / webhooks_test)forms:test

このページは Markdown でも読めます。AI エージェントには llms.txt(目次)か llms-full.txt(全文)を渡してください。