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 a secret unique to each API key. The signature covers the raw request body.
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));}Getting your webhook secret
Section titled “Getting your webhook secret”In the dashboard, go to API Keys → [key name] → Webhooks. The signing secret is shown there. It starts with nz_whsec_.
Replay protection
Section titled “Replay protection”Always verify both the signature and the created_at timestamp in the event body. Reject events with created_at more than 5 minutes in the past to prevent replay attacks.