Перейти к содержимому
Delivery API
Прежде чем рассчитывать на какую-либо функцию, проверьте статус возможностей.

Справочник

Вебхуки

Подписанные уведомления, которые Atlas отправляет вашему сайту при публикации контента, чтобы вы могли обновить именно затронутые страницы.

Эта страница переведена с английского. При любых расхождениях действует английская версия. Читать на английском

Создавайте вебхуки в Studio в разделе Integrations → Webhooks. У каждого есть HTTPS-адрес, получаемые события и секрет подписи, начинающийся с 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…
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.

Записывайте в журнал тип события и идентификатор доставки, но никогда — тело или секрет.

Тело запроса — это полезная нагрузка события. Для content.page.published это { "pageId", "route", "revision" }. Тип события указан в заголовке X-Atlas-Event.

Вебхуки настраиваются один раз, в Development, и также получают события с рабочего сайта. В каждой полезной нагрузке есть 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 Поступил новый лид (только идентификаторы, без персональных данных)
lead.merged Лид объединён с другим (только идентификаторы)
bot.published Чат-бот опубликован

Atlas ждёт вашего ответа до 10 секунд и не следует перенаправлениям. Используйте историю доставок в Studio, чтобы изучать полезные нагрузки и сбои.