Arquitectura

Última actualización: Aug 31, 2026Sección: Integraciones

Notificación IndexNOW (endpoint del integrador)

Cuando el contenido de Blog o Market se publica, actualiza, despublica o elimina, Mailoo puede hacer POST de identificadores a tu sitio. construyes las URLs públicas de las páginas y las envías a IndexNow. Mailoo no llama a IndexNOW directamente y no envía URLs absolutas.

Las operaciones de publicación y escritura de catálogo en Mailoo siempre tienen éxito incluso si tu endpoint no existe o devuelve un error (fire-and-forget). Mailoo registra el resultado en la fila de contenido como indexNowStatus.

Relacionado: Blog CMS --- blog-headless-cms{.interpreted-text role="doc"}; catálogo de mercado --- market-catalog-external-api{.interpreted-text role="doc"}; ejemplo de blog con Next.js --- blog-nextjs-example{.interpreted-text role="doc"}; HMAC de webhook de entrega (misma fórmula de firma) --- transactional-email{.interpreted-text role="doc"}.

Arquitectura

  • Activador: Después de una escritura exitosa de artículo de Blog o producto de Market (o variante de producto publicado).
  • Payload: IDs de proyecto/integración/contenido, slug de blog opcional, locales y action --- sin URLs de páginas.
  • Tu trabajo: Mapear ids → URLs públicas → API de IndexNOW con tu clave.
  • Estado en el contenido: PENDINGNOTIFIED | FAILED, o SKIPPED cuando indexNow no está configurado. null significa nunca intentado (p. ej. solo borrador).

Configuración

Por integración BLOG o MARKET:

  • Panel de control → Conexión y ajustes → Notificación IndexNOW
  • BLOG + MCP / API de gestión: GET/PATCH /api/v1/blog/{projectUid}/integrations/{integrationId}/settings (campo indexNow; el GET saneado expone notifyUrl + hasSecret). Herramienta MCP manage_blog_integration_settings --- consulta mailoo-mcp{.interpreted-text role="doc"}.
  • O PATCH /api/v1/projects/{uid}/integrations/{id} con cuerpo:
{
  "indexNow": {
    "notifyUrl": "https://www.example.com/api/indexnow/notify",
    "secret": "your-signing-secret"
  }
}

Envía "indexNow": null para limpiar. Las respuestas saneadas de la API exponen notifyUrl y hasSecret (nunca el secreto sin procesar).

Si notifyUrl / secret no están establecidos, Mailoo establece indexNowStatus en ``SKIPPED`` y no hace llamada HTTP a tu sitio.

Contrato del endpoint

Método / URL: POST a la notifyUrl configurada.

Cabeceras:

  • Content-Type: application/json
  • X-Mailoo-Event: indexnow.notify
  • X-Mailoo-Signature: t={unixSeconds},v1={hex} --- v1 es HMAC-SHA256 de "{timestamp}.{rawBody}" usando indexNow.secret (misma fórmula que los webhooks de entrega transaccional).

Cuerpo (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"
}

Campos por tipo

  • kind --- blog_post o market_product
  • contentId --- id del artículo o id del producto
  • slug --- slug del artículo (solo blog; omitido para market)
  • locales --- blog: en más claves del JSON locales del artículo; market: defaultCatalogLocale o en
  • action --- published, updated, unpublished o deleted

Cuándo dispara Mailoo

  • Crear con PUBLISHEDpublished
  • Actualizar que se convierte o permanece PUBLISHEDpublished / updated
  • El estado deja PUBLISHEDunpublished
  • Eliminar mientras está publicado → deleted (sin actualización de fila de estado después)
  • Escrituras solo de borrador → sin notificación; indexNowStatus permanece en null

Respuestas esperadas

  • 2xx --- aceptado (puedes encolar IndexNOW de forma asíncrona). Mailoo establece NOTIFIED.
  • 404 / 5xx / red / timeout --- Mailoo establece FAILED. La publicación de contenido ya fue confirmada.
  • Configuración faltante --- SKIPPED sin solicitud.

Valores de indexNowStatus

  • PENDING --- notificación en curso
  • NOTIFIED --- el integrador devolvió 2xx
  • SKIPPED --- sin configuración indexNow en la integración
  • FAILED --- solicitud fallida o no-2xx
  • null --- no aplica / nunca intentado

Responsabilidades del integrador

  1. Verifica X-Mailoo-Signature (rechaza firmas inválidas).
  2. Resuelve URL(s) públicas desde kind, contentId / slug y locales.
  3. Llama a IndexNOW con tu clave (y archivo de clave del host según lo requiera IndexNOW).
  4. Devuelve 2xx rápidamente; haz trabajo pesado de forma asíncrona si es necesario.

Ejemplo con 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 })
}

Requisitos previos

  • Integración BLOG o MARKET
  • indexNow.notifyUrl + secret configurados (opcional; sin ello el estado es SKIPPED)
  • Tu sitio implementa el endpoint de notificación y el alojamiento de la clave IndexNOW

Ejemplo: mailoo.app como integrador

El sitio de marketing de Mailoo es tanto un consumidor de Blog como un integrador de IndexNOW para esa integración de Blog. Patrón que puedes replicar:

  1. Entorno solo del servidor en el sitio: secreto de firma compartido, clave IndexNOW y SITE_URL público.
  2. Aloja el archivo de clave IndexNOW en https://{your-domain}/{key}.txt.
  3. Implementa POST /api/indexnow/notify que verifica HMAC, construye URLs públicas desde el payload y las envía a https://api.indexnow.org/indexnow.
  4. En la integración de Blog, establece notifyUrl a ese endpoint y secret al mismo secreto de firma (panel de control o MCP manage_blog_integration_settings).