Skip to main content
Surge signs every outbound webhook request following the Standard Webhooks specification. Verifying the signature confirms that the request came from Surge and wasn’t tampered with in transit.

The three headers

Surge sets these headers on every webhook POST: The webhook-signature header may contain multiple v1,<signature> values separated by spaces if your project has multiple signing secrets (during key rotation). Accept the request if any signature verifies successfully.

Signing algorithm

Surge computes the signature as:
The secret is base64-encoded and prefixed with whsec_ in the dashboard. Strip the prefix and base64-decode it before using it as the HMAC key. The signed message is the string from the webhook-id request header, a literal ., the integer from the webhook-timestamp request header, a literal ., and then the raw request body, all concatenated without any separating whitespace beyond the . characters.

Replay protection

The webhook-timestamp lets you reject replays. Surge recommends rejecting requests where webhook-timestamp is more than five minutes old. Most Standard Webhooks library implementations enforce this tolerance window automatically.

Verification examples

Finding your webhook secret

Your signing secret is shown in the dashboard on the top-level Webhooks page, next to each endpoint URL. It looks like whsec_<base64-encoded-bytes>.

Deprecated header

Earlier Surge versions used surge-signature instead of webhook-signature. If you are still reading surge-signature, migrate to webhook-signature. See Deprecation Notices.