コンテンツにスキップ
Delivery API
機能を前提に計画する前に、機能の提供状況をご確認ください。

リファレンス

Webhook

コンテンツの公開時に Atlas がウェブサイトへ送る署名付き通知で、影響を受けたページだけを正確に更新できます。

このページは英語から翻訳されたものです。内容に相違がある場合は、英語版が優先されます。 英語版を読む

Webhook は Studio の Integrations → Webhooks で作成します。それぞれに、HTTPS の URL、受信するイベント、whsec_ で始まる署名シークレット(一度だけ表示)があります。

Atlas は、公開されている HTTPS アドレスにのみ配信します。プライベートネットワークのアドレスは拒否され、プレーンな HTTP は、開発中の localhost に対してのみ許可されます。

POST https://your-site.example/api/atlas/webhook
Content-Type: application/json
X-Atlas-Event: content.page.published
X-Atlas-Delivery: <unique delivery id>
X-Atlas-Signature: t=1761210000,v1=5f2b…

すべてのリクエストを検証する

Section titled “すべてのリクエストを検証する”
app/api/atlas/webhook/route.ts
import { createHmac, timingSafeEqual } from 'node:crypto';
import { revalidatePath, revalidateTag } from 'next/cache';
const seen = new Set<string>(); // use a shared store (Redis, KV) when you run several instances
export async function POST(request: Request) {
const body = await request.text(); // the raw body, before any JSON parsing
const header = request.headers.get('x-atlas-signature') ?? '';
const parts = Object.fromEntries(header.split(',').map((part) => part.split('=', 2)));
const timestamp = Number(parts.t);
if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > 300)
return new Response(null, { status: 400 });
const expected = createHmac('sha256', process.env.ATLAS_WEBHOOK_SECRET!)
.update(`${timestamp}.${body}`)
.digest();
const given = Buffer.from(String(parts.v1 ?? ''), 'hex');
if (given.length !== expected.length || !timingSafeEqual(given, expected)) {
return new Response(null, { status: 401 });
}
const delivery = request.headers.get('x-atlas-delivery') ?? '';
if (seen.has(delivery)) return new Response(null, { status: 200 }); // already handled
seen.add(delivery);
const payload = JSON.parse(body); // e.g. { pageId, route, revision } for content.page.published
if (typeof payload.route === 'string') revalidatePath(payload.route);
else revalidateTag('atlas'); // entries, globals, translations: refresh everything tagged 'atlas'
return new Response(null, { status: 200 });
}

チェックの順序は次のとおりです。

  1. リクエストの生のボディを使う。
  2. 5 分より古いタイムスタンプを拒否する。
  3. 署名シークレットで HMAC-SHA256("<t>.<raw body>") を計算し、定数時間で比較する。
  4. 繰り返された X-Atlas-Delivery の ID は無視する。

ログに残すのはイベントタイプと配信 ID だけにし、ボディやシークレットは決して記録しないでください。

リクエストボディは、イベントのペイロードです。content.page.published の場合は { "pageId", "route", "revision" } です。イベントタイプは X-Atlas-Event ヘッダーに入っています。

Webhook は開発環境で 1 回設定するだけで、ライブウェブサイトのイベントも受信します。各ペイロードには environment("development" または "production")が含まれるため、両者を区別できます。

イベント 発生するタイミング
content.page.published ページが公開された、またはロールバックされた
content.page.unpublished ページがウェブサイトから取り下げられた
content.page.route.changed ページが新しいアドレスに移動した(リダイレクトが追加される)
content.entry.published コレクションのエントリーが公開された
content.entry.unpublished コレクションのエントリーがウェブサイトから取り下げられた
content.global.published ヘッダー、フッター、その他のグローバルが公開された
content.translation.published 翻訳が公開された
contract.activated 新しいサイトコントラクトが有効化された
seo.redirects.changed リダイレクトが変更された
media.asset.uploaded メディアファイルがアップロードされた
form.published フォームが公開された
form.submission.accepted フォームの送信が受理された
lead.created 新しいリードが届いた(ID のみで、個人データは含まない)
lead.merged リードが別のリードに統合された(ID のみ)
bot.published チャットボットが公開された

Atlas は応答を最大 10 秒待ち、リダイレクトには従いません。ペイロードや失敗を確認するには、Studio の配信履歴を使ってください。