Webhooks
The Webhooks collection (packages/payload-preset) is the integration mechanism itself, not an integration with any one third-party service - register any URL and it gets notified when content changes. No vendor is hardcoded, so it works equally well for a Slack incoming webhook, a Zapier catch hook, a static-site rebuild trigger, or your own custom endpoint.
Configuring one
In Payload admin, go to Webhooks and create an entry with a name, the target url, a secret, and which events it should fire for. Both read and write access require a logged-in user, since a webhook's secret is sensitive.
Events
page.published- fires whenever a page's_statusbecomes (or stays)"published". A plain autosaved draft never fires this - only an actual publish does.page.deleted- fires whenever a page is deleted, published or not.
Both are dispatched from the Pages collection's afterChange/afterDelete hooks (see packages/payload-preset/src/webhooks/dispatch.ts), so they fire no matter how the change happens - the admin panel, the REST/GraphQL API, or the Local API - not just through this app's own server actions.
Payload shape
{
"event": "page.published",
"slug": "home",
"locale": "en",
"title": "Home",
"timestamp": "2026-01-01T12:00:00.000Z"
}Verifying the signature
Every request carries an X-Olgax-Signature header - sha256=<hex>, an HMAC-SHA256 of the raw request body keyed with that webhook's own secret (the same convention GitHub and Stripe use for their webhooks). Verify it before trusting the payload:
import { createHmac, timingSafeEqual } from "crypto";
function isValid(secret: string, rawBody: string, header: string | null) {
if (!header) return false;
const expected = `sha256=${createHmac("sha256", secret).update(rawBody).digest("hex")}`;
return (
header.length === expected.length &&
timingSafeEqual(Buffer.from(header), Buffer.from(expected))
);
}A slow or unreachable receiver never blocks or fails the publish/delete that triggered it - dispatch happens in parallel with a 5-second timeout per request, and a failure is swallowed rather than surfaced to the editor.