Skip to main content

Confirm

Are you sure?

Changelog · August 30, 2026

Signed webhooks

Your endpoint can reject anything that didn't come from URLpipe.

By · Last updated: August 2026

TL;DR

Webhook deliveries can now be signed. Turn signing on per project and every delivery carries X-URLpipe-Timestamp and X-URLpipe-Signature: v1=<hex>, an HMAC-SHA256 of "<timestamp>.<raw body>" with the project's secret. Rotating the secret signs with both keys for 24 hours so nothing in flight is rejected.

Free plan, no credit card. 1,000 credits a month.

An async result used to arrive as a bare POST, and nothing in it said who sent it. The scheme is the industry-standard one, so a verifier you already have works: the timestamp is inside the signed string, so a captured delivery can't be replayed with a fresh timestamp, and the signature is over the exact bytes sent, so verify against the raw body.

Signing is off by default and switched on per project, because the order is yours: deploy verification first, then turn signing on. Turning it on can't break a correct consumer — the body is byte-identical and the signature rides in headers.

Verify a delivery
import hmac, hashlib

def verify(secret: str, timestamp: str, raw_body: bytes, header: str) -> bool:
    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
    signatures = [part.removeprefix("v1=") for part in header.split(",")]
    return any(hmac.compare_digest(expected, sig) for sig in signatures)

The header can carry two signatures during a rotation, so a verifier should accept any match. Revoke the old secret early if it leaked.

FAQ

Frequently asked questions

Are webhooks signed by default?
No. Signing is switched on per project, so you can deploy verification before deliveries start carrying signatures.
What exactly is signed?
The string "<timestamp>.<raw body>", with HMAC-SHA256 and your project's signing secret.
What happens when I rotate the secret?
For 24 hours each delivery carries two signatures, newest first; accept either, then revoke the old secret.

Try it on the free plan.

Free plan, no card. Confirm your email and your API key is live — you'll be making real requests in minutes.