x-contentful-signature header. Register the credential on your endpoint and webhook.co verifies every captured request against the exact bytes it received, then records the outcome — with a named reason when it fails.
Get the signing secret
In the space, open Settings → Webhooks → the Settings tab and enable request verification, which generates the signing secret. See Contentful’s own webhook documentation for the current steps. It is space-level — one secret covers every webhook in the space — and you cannot copy it again once you leave that view.Register it on your endpoint
How the signature is checked
- Signed message — a canonical request
METHOD\nNORMALIZED_PATH\nHEADERS_SECTION\nRAW_BODY, where HEADERS_SECTION is exactly the headers named inx-contentful-signed-headers(key:value, key lowercased, sorted by key, joined by;). - Algorithm — HMAC-SHA256, hex-encoded.
- Key — registered secret is a 64-char string used verbatim as the UTF-8 HMAC key.
- Signature format — lowercase-hex 32-byte HMAC-SHA256 MAC.
- Timestamp — read from the
x-contentful-timestampheader. - Also signed —
x-contentful-signed-headers. These header values are folded into the signed message, so they must reach us unmodified.
Replay window
Because the timestamp is signed, webhook.co enforces a 30-second tolerance: a request whose signed timestamp is older than that fails verification rather than being accepted as a possible replay.What makes this one different
- The signed message’s header section is DYNAMIC:
x-contentful-signed-headerslists which headers are folded in, so the canonical string shape varies per request. - Canonical =
METHOD\nNORMALIZED_PATH\nHEADERS_SECTION\nRAW_BODY; signed headers arekey:value, key lowercased+trimmed, sorted by key, joined by;(the signed-headers HEADER itself uses,). - One-sided 30-second TTL against
x-contentful-timestamp(milliseconds); the timestamp is itself a signed header, so replay is also bound in the signature.
Confirm
verified; one that does not shows failed, with the reason named.