Webhook
通知先の登録、署名検証、イベント、テスト送信、配送失敗への対処。
Webhookは、コンテンツの変更を外部のURLへHTTP POSTで通知する機能です。サイトの再ビルドやキャッシュ再検証に使います。記事本文を届けるのではなく、変更を知らせる小さなJSONを送ります。
設定にはオーナー権限と、外部からアクセスできるHTTPSの受信URLが必要です。
1. 通知先を準備する
ホスティング先のデプロイフック、または自分のアプリの受信処理を用意します。Next.jsの再検証に使う場合は、プラグインのnextRevalidateを利用できます。
自前の受信処理では、通知を受けて何を更新するか決めます。記事が削除された場合や、entryがないテスト通知も扱えるようにしてください。
2. Webhookを登録する
- 対象APIの設定画面を開きます。
- Webhookの追加から、名前・通知先URLを入力します。
- 署名検証する場合はシークレットを設定します。
- 保存し、有効になっていることを確認します。
1つのAPIにつき5件まで登録できます。イベントごとの選択はなく、登録したAPIの各イベントを通知します。不要なイベントは受信側で判定します。一時停止するときは無効に切り替えます。
シークレットは受信側の設定にも同じ値を登録します。APIキーとは別の値です。省略すると署名ヘッダーは送られません。
通知先はHTTPSのみです。localhost、プライベートIP、リンクローカルIP、.local、.internalなどへの通知はできません。リダイレクトも追跡しないため、最終的な受信URLを設定してください。
3. テスト送信する
一覧のテスト送信を実行し、受信先のログと送信結果を確認します。2xxが返れば配送成功です。テストではeventがwebhook.test、entryがnullになります。
テスト送信は、過去に失敗したイベントの再送ではありません。 実際の記事更新の動作確認には、対象記事を保存して受信側まで確認してください。
イベント
| イベント | 発生する操作 |
|---|---|
entry.created | 新規保存。下書きの作成も含む |
entry.updated | 既存記事の保存、手動の公開状態変更、履歴の復元など |
entry.deleted | コンテンツの削除 |
entry.published | 予約公開を定期処理で確定 |
entry.unpublished | 日時による公開終了を定期処理で確定 |
webhook.test | テスト送信 |
手動で「公開」にして保存したときは、作成/更新イベントです。公開に関する処理をentry.publishedだけに限定すると、手動公開を取りこぼします。また、公開から下書きへの変更では、entry.updatedの新しい状態がdraftになるため、古い公開ページの無効化も必要です。
ペイロードとヘッダー
{
"event": "entry.updated",
"workspace": "your-workspace",
"api": "blog",
"entry": { "id": "abcDEF123456", "status": "published" },
"triggeredAt": "2026-09-01T01:00:00.000Z"
}entry.statusはdraft・published・scheduled・closedです。削除通知には削除前の状態が入ります。本文が必要なら、必要なタイミングで配信APIから取得します。
| ヘッダー | 値 |
|---|---|
content-type | application/json |
user-agent | genko-webhook/1.0 |
x-genko-event | イベント名 |
x-genko-signature | シークレット設定時のみ。sha256=に続くHMAC-SHA256の16進文字列 |
署名を検証する
次はWeb標準のRequest/Responseを使う受信処理の例です。署名はJSONへ変換する前の、生の本文に対して確認します。
import { verifyGenkoSignature } from "@genko-me/sdk";
export async function POST(request: Request) {
const secret = process.env.GENKO_WEBHOOK_SECRET;
if (!secret) return new Response("Webhook secret is not configured", { status: 500 });
const rawBody = await request.text();
const valid = await verifyGenkoSignature({
secret,
rawBody,
signatureHeader: request.headers.get("x-genko-signature"),
});
if (!valid) return new Response("Invalid signature", { status: 401 });
const payload = JSON.parse(rawBody);
// 利用するworkspace・api・eventと、必要な値の形を検証してから処理します。
return Response.json({ received: true, event: payload.event });
}この例は受信確認までです。実際には再検証や処理キューへの登録など、必要な処理を追加します。重い処理を同期で待たず、同じ更新を繰り返し処理しても破綻しない設計にしてください。
配送の制限と失敗時
タイムアウトは10秒で、自動リトライはありません。管理画面で直近の結果を確認し、受信先のログと照合します。
| 結果 | 確認すること |
|---|---|
| 301/302など | リダイレクト先の最終URLを登録しているか |
| 401 | シークレットが一致するか。生の本文で検証しているか |
| 404 | 受信ルートが本番へデプロイされているか |
| タイムアウト | 10秒以内に応答できるか |
| 成功だが表示が古い | 受信後の再ビルド・再検証対象が正しいか |
失敗した更新を取り戻す場合は、受信側で最新データを取り直す、再ビルドを手動実行するなどの方法を用意してください。テスト送信の成功だけでは、失敗した処理を復旧したことにはなりません。
最終更新: 2026年9月5日