# Verify webhook signatures

Verify the exact Beacon webhook body before processing a lifecycle event.

Use the raw request body and the one-time signing secret from Beacon.

```ts
import {
  verifyBeaconWebhookSignature,
  type BeaconWebhookEvent,
} from "@beacon/sdk";

export async function POST(request: Request) {
  const rawBody = await request.text();
  const valid = await verifyBeaconWebhookSignature({
    rawBody,
    secret: process.env.BEACON_WEBHOOK_SECRET!,
    signatureHeader: request.headers.get("x-beacon-signature"),
  });

  if (!valid) return new Response("Invalid signature", { status: 401 });

  const event = JSON.parse(rawBody) as BeaconWebhookEvent;
  await saveEventOnce(event.id, event);
  return new Response(null, { status: 204 });
}
```

Do not parse and reserialize the body before verification. The default timestamp tolerance is five minutes.

Use a unique database constraint on `event.id`. Beacon keeps the event ID stable when it retries a delivery.

Read [Publication webhooks](/docs/developers/api/webhooks) for event names, retry rules, and ordering behavior.
