What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
Administrators
This guide covers configuring webhooks in Agility CMS for cache invalidation and automation, including secure delivery, retries and delivery history.
This guide covers configuring webhooks in Agility CMS for cache invalidation and automation.
Webhooks allow Agility CMS to notify your application when content changes, enabling automatic cache invalidation and other automation.
When you add a webhook you choose which categories of event it subscribes to:
The state value in the payload tells you which specific event occurred. Unpublishing and deleting both arrive as Deleted. For every event, its payload and the headers that come with it, see the Webhook Events and Payload Reference.
Create a webhook endpoint in your application:
// app/api/revalidate/route.ts
export async function POST(request: Request) {
// Verify the signature (see Securing your webhook, below)
// Process webhook event
// Revalidate cache
return Response.json({ revalidated: true })
}
Your webhook endpoint is a public URL. Turn on secure delivery so your application can prove that a request genuinely came from your Agility instance and was not modified in transit.
When you enable it, Agility generates a signing secret and signs every delivery using the open Standard Webhooks specification. Your endpoint verifies the signature with any off-the-shelf Standard Webhooks library (for Node.js, standardwebhooks on npm).
Full instructions, including verification samples for Node.js, C#, Python and PHP: Verifying Signed Webhooks.
Viewing or rolling a signing secret requires Full Control. Users with a lower permission level can still create and manage webhooks, but the secret is hidden from them.
⚠️ There is no way to secure a webhook with a security key or a custom header. Agility does not send
AGILITY_SECURITY_KEY, or any other shared secret, with a webhook — that key is used for preview authentication and is unrelated. An earlier version of this guide showed a validation step based on it; that check could never succeed, because the header it looked for was never sent. Secure delivery is the way to verify a webhook.
By default a delivery is attempted once. If your endpoint is briefly unavailable, that delivery is lost.
Tick Enable retries on the webhook to have Agility retry a failed delivery, and choose:
fast (30 seconds), standard (5 minutes) or slow (30 minutes) base interval, growing exponentially with jitterDelivery is at-least-once, so design your endpoint to tolerate receiving the same event twice. Use the webhook-id header as an idempotency key — it is unique per event, stable across retries, and sent on every delivery whether signed or not.
The examples below are publish events. Sample payloads for every event, including unpublish and delete, are in the Webhook Events and Payload Reference.
{
"state": "Published",
"instanceGuid": "your-instance-guid",
"languageCode": "en-us",
"referenceName": "posts",
"contentID": 204,
"contentVersionID": 1287,
"changeDateUTC": "2025-12-08T15:12:10.883Z"
}
{
"state": "Published",
"instanceGuid": "your-instance-guid",
"languageCode": "en-us",
"pageID": 2,
"pageVersionID": 114,
"changeDateUTC": "2025-12-08T15:12:10.883Z"
}
export async function POST(request: Request) {
// Read the raw body first if you are verifying the signature —
// re-serializing the JSON will break verification.
const data = await request.json()
// Publish, unpublish and delete (unpublish and delete both arrive as "Deleted")
if (data.state === "Published" || data.state === "Deleted") {
// Revalidate content tags
if (data.referenceName) {
revalidateTag(`agility-content-${data.referenceName}-${data.languageCode}`)
revalidateTag(`agility-content-${data.contentID}-${data.languageCode}`)
}
// Revalidate page tags
if (data.pageID) {
revalidateTag(`agility-page-${data.pageID}-${data.languageCode}`)
}
// The payload has no URL path. To revalidate a path, look the item up
// in your sitemap by contentID or pageID, then call revalidatePath.
}
return Response.json({ revalidated: true })
}
webhook-id to discard events you have already handledEvery webhook has a History action in Settings → Webhooks. It shows each delivery attempt: the status code your endpoint returned, which attempt it was, when the next retry is scheduled, and the payload and response bodies. That is usually faster than reproducing the problem.
Delivery history is go-forward only. A webhook created before this feature shipped shows an empty history until it fires again — that is expected, not a fault.
Issue: Webhook not receiving events
Solutions:
Issue: Your endpoint rejects deliveries as unsigned or invalid
Solutions:
Next: Troubleshooting - Admin troubleshooting