Webhook signatures
Every webhook request includes an X-Nuez-Signature header. Verify it before processing the event.
How signatures work
Section titled “How signatures work”nuez signs each webhook with HMAC-SHA256 using the secret you provided when configuring your webhook (PUT /v1/webhook — one endpoint and one secret per user, not per API key). The signature covers the raw request body exactly as sent, before JSON parsing.
Verifying in Go
Section titled “Verifying in Go”import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "io" "net/http")
func verifyWebhook(r *http.Request, secret string) bool { sig := r.Header.Get("X-Nuez-Signature") body, _ := io.ReadAll(r.Body)
mac := hmac.New(sha256.New, []byte(secret)) mac.Write(body) expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(sig), []byte(expected))}Verifying in Python
Section titled “Verifying in Python”import hmacimport hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool: expected = "sha256=" + hmac.new( secret.encode(), body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature)Verifying in TypeScript
Section titled “Verifying in TypeScript”import { createHmac, timingSafeEqual } from "crypto";
function verifyWebhook(body: Buffer, signature: string, secret: string): boolean { const expected = "sha256=" + createHmac("sha256", secret) .update(body) .digest("hex"); return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));}Your webhook secret
Section titled “Your webhook secret”Unlike most providers, nuez doesn’t generate this secret for you — you choose it yourself when calling PUT /v1/webhook (minimum 16 characters). Store it securely; nuez only keeps it to sign outgoing requests, it isn’t retrievable via GET /v1/webhook. See Webhook management.
Replay protection
Section titled “Replay protection”Verify the signature, and also check the timestamp field in the JSON body (see Webhook events for the envelope shape) — reject events with a timestamp more than a few minutes in the past to guard against replay of an intercepted request.