Verify webhook signatures

Verify the X-MakeForm-Signature header before you parse a webhook body. The signature is an HMAC-SHA256 digest of the exact raw body bytes, keyed with your webhook signing secret. Makeform sends the header when the webhook has a signing secret. A GET webhook request has no body or signature.

For requests with a body, the signature header has this format:

sha256=<hex>

Get the signing secret from your webhook settings. A generated secret is shown once when the webhook is created; the webhook list shows only whether a secret exists. If you provide a custom secret, it must be 16–256 characters with no whitespace. Saving a changed secret in the dashboard overwrites the existing one; MCP has no rotate action.

Node.js

Pass the exact request bytes as a Buffer, along with the signature header and signing secret. The function verifies the signature before parsing JSON.

import { createHmac, timingSafeEqual } from "node:crypto"; function parseMakeformWebhook(rawBody, signature, secret) { if (!signature?.startsWith("sha256=")) { throw new Error("Invalid Makeform webhook signature"); } const receivedHex = signature.slice("sha256=".length); if (!/^[0-9a-f]{64}$/i.test(receivedHex)) { throw new Error("Invalid Makeform webhook signature"); } const received = Buffer.from(receivedHex, "hex"); const expected = createHmac("sha256", secret).update(rawBody).digest(); if (received.length !== expected.length || !timingSafeEqual(received, expected)) { throw new Error("Invalid Makeform webhook signature"); } return JSON.parse(rawBody.toString("utf8")); } // Call with the exact request bytes, X-MakeForm-Signature header, and signing secret.

Python

Pass the raw request body as bytes. A missing signature header returns an invalid result before JSON parsing.

import hashlib import hmac import json def parse_makeform_webhook(raw_body: bytes, signature: str | None, secret: str): if not signature or not signature.startswith("sha256="): raise ValueError("Invalid Makeform webhook signature") expected = "sha256=" + hmac.new( secret.encode("utf-8"), raw_body, hashlib.sha256, ).hexdigest() if not hmac.compare_digest(signature, expected): raise ValueError("Invalid Makeform webhook signature") return json.loads(raw_body) # Call with the exact request bytes, X-MakeForm-Signature header, and signing secret.

You can test signature handling with the MCP test_webhook action. It sends a test delivery with the same headers and signature as a real delivery. Deliveries are not retried, including after a 5xx or 429 response from your endpoint.

Do not parse and re-serialize the JSON before verification. Verify the original bytes received by your endpoint.