웹훅
콘텐츠가 게시될 때 Atlas가 웹사이트로 보내는 서명된 알림입니다. 영향을 받은 페이지만 정확히 새로 고칠 수 있습니다.
이 페이지는 영어에서 번역되었습니다. 내용이 다를 경우 영어 버전이 우선합니다. 영어로 읽기
Studio의 Integrations → Webhooks에서 웹훅을 만듭니다. 각 웹훅에는 HTTPS URL, 수신할 이벤트, 한 번만 표시되는 whsec_로 시작하는 서명 시크릿이 있습니다.
Atlas는 공개 HTTPS 주소로만 전달합니다. 사설 네트워크 주소는 거부되며, 일반 HTTP는 개발 중 localhost에만 허용됩니다.
POST https://your-site.example/api/atlas/webhookContent-Type: application/jsonX-Atlas-Event: content.page.publishedX-Atlas-Delivery: <unique delivery id>X-Atlas-Signature: t=1761210000,v1=5f2b…모든 요청 검증
섹션 제목: “모든 요청 검증”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 });}검사 순서는 다음과 같습니다.
- 원본 요청 본문을 사용합니다.
- 5분보다 오래된 타임스탬프는 거부합니다.
- 서명 시크릿으로
HMAC-SHA256("<t>.<raw body>")를 계산하고 상수 시간으로 비교합니다. - 반복되는
X-Atlas-DeliveryID는 무시합니다.
이벤트 유형과 전달 ID는 로그에 남기되, 본문이나 시크릿은 절대 남기지 마세요.
이벤트
섹션 제목: “이벤트”요청 본문이 이벤트의 페이로드입니다. content.page.published의 경우 { "pageId", "route", "revision" }입니다. 이벤트 유형은 X-Atlas-Event 헤더에 있습니다.
웹훅은 개발 환경에서 한 번 설정하며 라이브 웹사이트의 이벤트도 함께 수신합니다. 각 페이로드에는 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의 전달 기록에서 페이로드와 실패를 확인하세요.