Когда контент Blog или Market публикуется, обновляется, снимается с публикации или удаляется, Mailoo может отправить POST с идентификаторами на ваш сайт. Вы формируете публичные URL страниц и отправляете их в IndexNow. Mailoo не вызывает IndexNOW напрямую и не отправляет абсолютные URL.
Публикация и запись данных каталога в Mailoo всегда завершаются успешно, даже если ваш эндпоинт недоступен или возвращает ошибку (fire-and-forget). Mailoo записывает результат в поле indexNowStatus строки контента.
Связанные материалы: блог CMS --- blog-headless-cms{.interpreted-text role="doc"}; каталог товаров --- market-catalog-external-api{.interpreted-text role="doc"}; пример Next.js для блога --- blog-nextjs-example{.interpreted-text role="doc"}; HMAC вебхуков доставки (та же формула подписи) --- transactional-email{.interpreted-text role="doc"}.
Архитектура
- Триггер: После успешной записи статьи блога или товара каталога (или варианта опубликованного товара).
- Полезная нагрузка: Идентификаторы проекта/интеграции/контента, опциональный
slugблога,localesиaction--- без URL страниц. - Ваша задача: Сопоставить идентификаторы → публичные URL → API IndexNOW с вашим ключом.
- Статус контента:
PENDING→NOTIFIED|FAILED, илиSKIPPEDеслиindexNowне настроен.nullозначает «не предпринималось» (например, только черновик).
Настройка
Для каждой интеграции BLOG или MARKET:
- Панель управления → Подключение и настройки → IndexNOW-уведомление
- BLOG + MCP / API управления:
GET/PATCH /api/v1/blog/{projectUid}/integrations/{integrationId}/settings(полеindexNow; санитизированный GET возвращаетnotifyUrl+hasSecret). MCP-инструментmanage_blog_integration_settings--- см.mailoo-mcp{.interpreted-text role="doc"}. - Или
PATCH /api/v1/projects/{uid}/integrations/{id}с телом:
{
"indexNow": {
"notifyUrl": "https://www.example.com/api/indexnow/notify",
"secret": "your-signing-secret"
}
}
Отправьте "indexNow": null для сброса. Санитизированные ответы API содержат notifyUrl и hasSecret (секрет в открытом виде никогда не возвращается).
Если notifyUrl / secret не заданы, Mailoo устанавливает indexNowStatus в ``SKIPPED`` и не выполняет HTTP-вызов вашего сайта.
Контракт эндпоинта
Метод / URL: POST на настроенный notifyUrl.
Заголовки:
Content-Type: application/jsonX-Mailoo-Event: indexnow.notifyX-Mailoo-Signature: t={unixSeconds},v1={hex}---v1--- HMAC-SHA256 строки"{timestamp}.{rawBody}"с использованиемindexNow.secret(та же формула, что и у вебхуков доставки транзакционных писем).
Тело (JSON):
{
"event": "indexnow.notify",
"kind": "blog_post",
"action": "published",
"projectUid": "…",
"integrationId": "…",
"contentId": "…",
"slug": "my-post",
"locales": ["en", "de"],
"timestamp": "2026-08-03T09:00:00.000Z"
}
Поля по типу
kind---blog_postилиmarket_productcontentId--- id статьи или id товараslug--- slug статьи (только для блога; отсутствует для каталога)locales--- блог:enплюс ключи из JSONlocalesстатьи; каталог:defaultCatalogLocaleилиenaction---published,updated,unpublishedилиdeleted
Когда Mailoo отправляет уведомление
- Создание со статусом
PUBLISHED→published - Обновление, при котором статус становится или остаётся
PUBLISHED→published/updated - Статус покидает
PUBLISHED→unpublished - Удаление в опубликованном состоянии →
deleted(обновления строки статуса после этого нет) - Запись только черновика → уведомление не отправляется;
indexNowStatusостаётсяnull
Ожидаемые ответы
- 2xx --- принято (вы можете поставить IndexNOW в очередь асинхронно). Mailoo устанавливает
NOTIFIED. - 404 / 5xx / сеть / таймаут --- Mailoo устанавливает
FAILED. Публикация контента уже зафиксирована. - Отсутствующая конфигурация ---
SKIPPEDбез запроса.
Значения indexNowStatus
PENDING--- уведомление в процессеNOTIFIED--- интегратор вернул 2xxSKIPPED--- нет конфигурацииindexNowна интеграцииFAILED--- запрос не удался или не-2xx ответnull--- не применимо / не предпринималось
Обязанности интегратора
- Проверить
X-Mailoo-Signature(отклонять невалидные подписи). - Сформировать публичный URL из
kind,contentId/slugиlocales. - Вызвать IndexNOW с вашим ключом (и файлом ключа хоста, как требует IndexNOW).
- Вернуть 2xx быстро; выполнять тяжёлые операции асинхронно.
Набросок для Next.js App Router
// app/api/indexnow/notify/route.ts
import { createHmac, timingSafeEqual } from 'node:crypto'
import { NextRequest, NextResponse } from 'next/server'
const SECRET = process.env.MAILOO_INDEXNOW_SECRET!
function verify(signatureHeader: string | null, body: string): boolean {
if (!signatureHeader) return false
const m = /^t=(\d+),v1=([a-f0-9]+)$/i.exec(signatureHeader.trim())
if (!m) return false
const [, t, v1] = m
const expected = createHmac('sha256', SECRET)
.update(`${t}.${body}`)
.digest('hex')
try {
return timingSafeEqual(Buffer.from(v1, 'hex'), Buffer.from(expected, 'hex'))
} catch {
return false
}
}
export async function POST(req: NextRequest) {
const raw = await req.text()
if (!verify(req.headers.get('x-mailoo-signature'), raw)) {
return NextResponse.json({ error: 'invalid signature' }, { status: 401 })
}
const payload = JSON.parse(raw) as {
kind: string
action: string
contentId: string
slug?: string
locales: string[]
}
// Build URLs from payload, then POST to https://api.indexnow.org/indexnow
void payload
return NextResponse.json({ ok: true })
}
Предварительные требования
- Интеграция BLOG или MARKET
indexNow.notifyUrl+secretнастроены (необязательно; без них статусSKIPPED)- Ваш сайт реализует эндпоинт уведомлений и хостинг ключа IndexNOW
Пример: mailoo.app как интегратор
Маркетинговый сайт Mailoo является одновременно потребителем блога и интегратором IndexNOW для этой интеграции Blog. Паттерн, который вы можете повторить:
- Серверные переменные окружения на сайте: общий секрет подписи, ключ IndexNOW и публичный
SITE_URL. - Разместите файл ключа IndexNOW по адресу
https://{your-domain}/{key}.txt. - Реализуйте
POST /api/indexnow/notify, который проверяет HMAC, формирует публичные URL из полезной нагрузки и отправляет их вhttps://api.indexnow.org/indexnow. - На интеграции Blog укажите
notifyUrlна этот эндпоинт иsecretравный тому же секрету подписи (панель управления или MCPmanage_blog_integration_settings).