Webhooks

Use webhooks to get notified about events in your Drupal site and trigger external workflows.

Creating a Webhook

You can create a webhook in the decoupled.io dashboard. You'll need to provide a URL for your webhook endpoint and select the events you want to subscribe to.

Event Payloads

When an event is triggered, decoupled.io will send a POST request to your webhook URL with a JSON payload. Here's an example of a payload for a `node.update` event:

{
  "event": "node.update",
  "entity": {
    "type": "article",
    "id": "your-article-uuid",
    "attributes": {
      "title": "My Updated Article"
    }
  }
}

Securing Your Webhooks

Secure your webhook endpoints by verifying incoming requests using the revalidation secret. This is the same secret used for on-demand ISR revalidation.

// app/api/webhook/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidate-secret');

  if (secret !== process.env.DRUPAL_REVALIDATE_SECRET) {
    return NextResponse.json(
      { message: 'Invalid secret' },
      { status: 401 }
    );
  }

  // Process webhook...
  return NextResponse.json({ message: 'Webhook received' });
}

Next.js Example

Here's how to create a Next.js API route (App Router) to handle incoming webhooks and trigger on-demand revalidation:

// app/api/webhook/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidate-secret');

  if (secret !== process.env.DRUPAL_REVALIDATE_SECRET) {
    return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
  }

  const body = await request.json();
  const { event, entity } = body;

  if (event === 'node.update' || event === 'node.insert') {
    console.log(`${entity.type} ${entity.id} was updated`);

    // Revalidate the specific path
    if (entity.path) {
      revalidatePath(entity.path);
    }

    // Revalidate listing pages
    revalidatePath('/articles');
  }

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