ProductsFor your stack

Webhooks

Know the moment anything changes.

Capa signs a POST to your endpoint for every publish, edit, upload and scheduled run. Failed deliveries retry for more than eight hours, and every attempt is kept, so you can see what happened and send it again.

Webhooks · Site rebuild
Site rebuildhttps://example.com/hooks/capa
Enabledwhsec_3f9a…
EventWhatResponseAttempt
instance.unpublishedWine list 2024200Attempt 2, same event id
publish.batch.completed31 entries, 0 failed200Attempt 1
instance.unpublishedWine list 2024503Retry in 1 min
media.uploadedhero-autumn.jpg200Attempt 1
instance.publishedAutumn menu200Attempt 1
Events

Eighteen events. Pick the ones you need.

Content, models, media and publishing runs, each with a description and a sample payload in the admin's subscription checklist.

Content
  • instance.created
  • instance.updated
  • instance.published
  • instance.unpublished
  • instance.deleted
Models
  • model.created
  • model.updated
  • model.published
  • model.deleted
Media
  • media.uploaded
  • media.updated
  • media.deleted
Publishing
  • publish.scheduled
  • publish.rescheduled
  • publish.cancelled
  • publish.failed
  • publish.batch.completed
Test
  • webhook.test

Subscribe to exact types or to a wildcard like instance.*, which also matches types added later. A test event only ever goes to the endpoint you are testing.

Verify

Proof it came from Capa. In one function.

  • Signed with HMAC-SHA256

    Every delivery signs its timestamp and exact body with your endpoint's secret. The SDK's check also refuses anything older than five minutes.

  • The same id on every retry

    The event id is also the Idempotency-Key header, unchanged across retries and redeliveries. Store it and skip a repeat.

  • Identity and links, not your content

    The body says what changed and where to read it. Turn on includeData for receivers that cannot call back.

  • Rotate without dropping a request

    For 24 hours after a rotation every delivery is signed with both secrets, so you can update your receiver whenever suits you.

app/hooks/capa/route.ts
import { verifyWebhookSignature } from "@capacms/sdk";

export async function POST(request: Request) {
  const body = await request.text();          // the raw body, as it arrived
  const ok = await verifyWebhookSignature({
    payload: body,
    header: request.headers.get("capa-signature") ?? "",
    secret: process.env.CAPA_WEBHOOK_SECRET!,
  });
  if (!ok) return new Response("bad signature", { status: 400 });

  const event = JSON.parse(body);
  if (await alreadyHandled(event.id)) return new Response("ok");
  await handle(event);
  return new Response("ok");
}
Retries

Your server was down. Nothing was lost.

Anything but a 2xx is a failure, redirects included. Capa tries again on a ladder that stretches across a working day.

  1. NowAttempt 1
  2. +1 minAttempt 2
  3. +5 minAttempt 3
  4. +30 minAttempt 4
  5. +2 hAttempt 5
  6. +6 hAttempt 6

8 h 36 min from the first attempt to the last, so a receiver that comes back inside a working day catches up on its own.

25 failures in a row, the first of them a day old, pause the endpoint. A burst of failures during an outage never costs you the endpoint.

Safe by default

Built for the night something breaks.

  • Transport

    HTTPS only

    A webhook body carries your titles and a signature. Plain HTTP to a public host is refused when you save the endpoint.

  • Network

    Private addresses refused, twice

    The host is checked when you save it and resolved again at every delivery, so a DNS change can never point a webhook inside a network.

  • Secrets

    Shown once

    The secret appears when you create or rotate an endpoint. Revealing it later needs its own permission, and every reveal is audited.

  • Redeliver

    Send it again

    Redeliver one delivery, everything that failed, or everything missed during a pause, with the count shown before anything is sent.

  • Log

    Every attempt kept

    Each delivery keeps the request and the response for 30 days. Quote the delivery id and the exact attempt is found.

  • Access

    People manage endpoints, keys do not

    Adding an endpoint takes a signed-in developer or admin. An API key can never forward your content somewhere new.

Your stack, in step with your content.

Add an endpoint in the admin, send a test event, and watch it land.