Skip to content
mxHeadless
REST API gateway for headless frontends on MODX 3. Resources, objects, OpenAPI, API keys, and OAuth
  1. Extras
  2. mxHeadless
  3. Operations
  4. ISR revalidation

ISR revalidation

Tags in meta.revalidate help invalidate headless frontend cache after MODX changes.

Flow

text
MODX mutation → outbox → worker POST → your /api/revalidate → Next.js / Nuxt cache purge

mxHeadless does not call the frontend synchronously inside the API HTTP request. Delivery is async via the webhook worker.

Tag format

Strings in meta.revalidate:

TagInvalidate when
mxheadless:resourcesAny resource change
mxheadless:resources:{id}One resource
mxheadless:uri:{path}Page by URI
mxheadless:context:{key}Context content
mxheadless:resources:listResource deleted (lists)
mxheadless:resources:{parentId}Child changed (parent menu)

Map tags to router paths in your revalidate handler.

Next.js App Router example

app/api/revalidate/route.ts:

typescript
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
import { createHmac, timingSafeEqual } from 'crypto';

export async function POST(request: NextRequest) {
  const secret = process.env.MXHEADLESS_WEBHOOK_SECRET ?? '';
  const rawBody = await request.text();
  const signature = request.headers.get('x-mxheadless-signature') ?? '';

  if (secret && !verifySignature(secret, rawBody, signature)) {
    return NextResponse.json({ error: 'invalid signature' }, { status: 401 });
  }

  const event = JSON.parse(rawBody) as {
    type: string;
    meta?: { revalidate?: string[] };
  };

  for (const tag of event.meta?.revalidate ?? []) {
    revalidateTag(tag);
  }

  return NextResponse.json({ revalidated: true, type: event.type });
}

function verifySignature(secret: string, body: string, header: string): boolean {
  const expected = 'sha256=' + createHmac('sha256', secret).update(body).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(header);
  return a.length === b.length && timingSafeEqual(a, b);
}

The subscription secret in MODX and the frontend env must match.

Subscription

  1. Row in mxheadless_webhook_subscriptions
  2. URL: https://frontend.example/api/revalidate
  3. Events: resources.* or *
  4. Shared secret with the frontend
  5. Worker on cron every minute

See also Webhooks and Next.js.