Webhook receiver
A webhook receiver in Node and Python (Flask) that verifies Standard Webhooks signatures on the raw body, replies fast, ignores duplicates and fetches job results.
Last updated
View as MarkdownThis recipe receives job.completed and lookup.completed events and verifies them before trusting them. There is a Node version with no framework and a Python version with Flask.
What rules does the receiver follow?
| Rule | Why |
|---|---|
| Verify the signature on the raw body | Re-serialized JSON changes the bytes, so the signature no longer matches |
| Reply with 2xx quickly, then do the work | Slow or failing endpoints are retried |
Ignore repeated webhook-id values | A delivery can arrive more than once |
| Fetch job results with your API key | Events never contain phone numbers or e-mail addresses |
What does verification look like?
import { verifyWebhook } from "mobilevalidate";
const raw = Buffer.concat(chunks); // the exact bytes received
const event = await verifyWebhook(raw, req.headers, process.env.MOBILEVALIDATE_WEBHOOK_SECRET);
res.writeHead(204).end(); // reply first
if (event.type === "job.completed") {
for await (const row of mv.jobs.results(event.data.id)) { /* … */ }
}from mobilevalidate import verify_webhook, WebhookVerificationError
@app.post("/webhooks/mobilevalidate")
def receive():
try:
event = verify_webhook(request.get_data(), request.headers, SECRET)
except WebhookVerificationError as e:
return str(e), 400
return "", 204verifyWebhook throws when the signature doesn't match or the timestamp is more than 5 minutes off. See Webhooks for the signature scheme and retry schedule.
How do I test it locally?
Sign a sample event with the CLI and send it with curl. No API key is needed for this:
export MOBILEVALIDATE_WEBHOOK_SECRET=whsec_$(printf 'local-test-secret' | base64)
npx mobilevalidate webhooks sign --secret "$MOBILEVALIDATE_WEBHOOK_SECRET" --file event.json > headers.txt
curl -i localhost:3000/webhooks/mobilevalidate -H 'content-type: application/json' \
-H "$(sed -n 1p headers.txt)" -H "$(sed -n 2p headers.txt)" -H "$(sed -n 3p headers.txt)" \
--data-binary @event.jsonTo receive real events, register an endpoint with a personal test key or a live key.
Frequently asked questions
Why does my signature check fail?
Usually because the body was parsed and re-serialized before verification. Verify the raw bytes exactly as received, with the endpoint's own whsec_ secret.
Can I use webhooks with the sandbox key?
No. The public sandbox key has no webhooks. Use a personal test key to register a test endpoint, or sign a sample event yourself with the CLI.

