Skip to main content

Signature verification

Every webhook request from Zenstep includes an X-Zenstep-Signature header containing an HMAC-SHA256 signature of the raw request body. You should verify this signature before processing any webhook payload.

Getting your webhook secret

When you create a webhook endpoint in the dashboard (Settings → Notifications → Add webhook), Zenstep generates a unique secret for that endpoint. Copy the secret immediately — it is only shown once. If you lose the secret, rotate it from the webhook settings page. All subsequent deliveries will use the new secret.

Verifying the signature


Security best practices

Always verify signatures — do not process webhook payloads without signature verification, even in development. Use the raw request body — compute the HMAC over the raw bytes of the request body before JSON parsing. Whitespace differences will cause signature mismatches. Use timing-safe comparison — always use crypto.timingSafeEqual (Node.js), hmac.compare_digest (Python), or hmac.Equal (Go) to compare the computed and received signatures. Standard string comparison is vulnerable to timing attacks. Store the secret in an environment variable — never hardcode the webhook secret in your source code. Reject requests without the header — if X-Zenstep-Signature is missing, return 401 immediately.

Replay attacks

To prevent replay attacks, Zenstep includes a timestamp field in every payload. Reject payloads where the timestamp is more than 5 minutes in the past:
Each delivery also has a unique id field. If your application requires strict idempotency, store processed delivery IDs and skip re-processing.