Skip to main content
Webhook signing is not enabled by default. Webhooks created through the dashboard have a secret key generated and stored, but the Signature header is not sent unless signing is explicitly enabled for the webhook. The information below describes how signing works when it is enabled.
When signing is enabled, every webhook request includes a Signature header containing an HMAC-SHA256 hash. You should verify this signature to ensure the request genuinely came from RMZ and was not tampered with in transit.

How Signing Works

  1. RMZ serializes the webhook payload to JSON
  2. The JSON string is signed using HMAC-SHA256 with your webhook’s secret key
  3. The resulting hex-encoded hash is sent in the Signature header
  4. Your server recomputes the hash and compares it to the header value
Signature: a1b2c3d4e5f6...

Verification Steps

1

Extract the signature

Read the Signature header from the incoming request.
2

Get the raw request body

Read the raw request body as a string. Do not parse it to JSON first — the signature is computed on the raw JSON string.
3

Compute the expected signature

Calculate HMAC-SHA256 of the raw body using your webhook’s secret key.
4

Compare signatures

Use a constant-time comparison to check that the computed hash matches the Signature header. Reject the request if they do not match.
Always use constant-time string comparison (e.g., hash_equals in PHP, hmac.compare_digest in Python) to prevent timing attacks.

Code Examples

const crypto = require("crypto");

function verifyWebhookSignature(rawBody, signatureHeader, secretKey) {
  const expectedSignature = crypto
    .createHmac("sha256", secretKey)
    .update(rawBody)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expectedSignature)
  );
}

// Express.js example
app.post("/webhooks/rmz", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["signature"];
  const secretKey = process.env.RMZ_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body.toString(), signature, secretKey)) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const payload = JSON.parse(req.body);
  console.log("Verified event:", payload.event);

  // Process the webhook...

  res.status(200).json({ received: true });
});

Important Notes

The signature is computed on the exact JSON string that RMZ sends. If you parse the JSON and re-serialize it, whitespace or key ordering differences could produce a different hash. Always verify against the raw request body.
If signing is not enabled for your webhook, the Signature header will not be present. The is_signed flag in the webhook configuration controls this. By default, webhooks created through the dashboard do not have signing enabled. You can still use the X-RMZ-REQUEST-ID header for tracking purposes.
Currently, the secret key is generated when the webhook is created and cannot be rotated independently. To get a new key, delete the webhook and create a new one. The new webhook will receive a fresh 28-character secret key.
Even if you choose not to verify signatures, always validate the payload structure before processing. Check that required fields exist and have expected types.