What is a webhook? How webhooks work in email, SMS and WhatsApp APIs
Editorial team · updated · facts checked
A webhook is an HTTP request that an app sends to a URL you choose when an event happens, so your code hears about the event instead of asking for it. When a text is delivered, a customer replies or an email bounces, the messaging provider sends the details to your endpoint (a URL on your server), and your endpoint answers with a 2xx status. No-code tools work the same way: an automation platform gives you a URL to paste into the provider's webhook setting.
Twilio calls them status callbacks, SendGrid an Event Webhook. Each provider sets its own rules; the closest shared rulebook is Standard Webhooks, an open specification (version 1.0.0) that Bird follows. We re-read every vendor page quoted below on 24 September 2026.
Webhook vs API polling
Polling means calling the API on a timer, say reading a message's status every 30 seconds until it is final. A webhook reverses the direction: the provider calls you.
| Polling the API | Webhook | |
|---|---|---|
| Who sends the request | Your code | The provider |
| When you learn of an event | At the next poll | When the provider sends it |
| Requests | One per check, most with no news | One per event, plus retries |
| What goes wrong | Rate limits, stale status | Missed, repeated, out-of-order or forged events |
Many apps use both: webhooks for speed, an occasional API read to catch what a webhook missed.
How webhook delivery works
- You register a URL in the dashboard, through an API or per message (Telnyx takes a
webhook_urlin the send request). - An event happens and the provider POSTs the details, usually as JSON. Twilio "occasionally adds parameters without advance notice", so don't reject unknown fields.
- Your endpoint answers
2xxbefore the timeout. Standard Webhooks recommends senders wait 15 to 30 seconds; some wait far less. Anything else is a failure: the provider retries on a schedule, then gives up.
The details differ by provider:
| Provider | Waits for your answer | Retries after a failure |
|---|---|---|
| Twilio | 15 s (5 s to connect), by default | 1, only when the connection fails, so a 500 from your app isn't retried; up to 5 with URL overrides |
| Telnyx messaging | 2 s | Up to 3 attempts per URL, then the failover URL if set |
| Plivo | Not stated | 3, after 60, 120 and 240 s |
| Postmark | Not stated | 6, 1 to 15 minutes apart |
| SMTP2GO | 10 s | Up to 35 over 48 hours |
| Bird, Resend | 15 s at Bird | Same schedule: 8 attempts over about 27.5 hours |
Your status code matters too: Postmark and Sinch don't retry most 4xx responses, so a 401 from a broken auth check loses the event, while Bird retries every non-2xx. Botmaker pauses for 10 minutes after more than 100 failures in 10 minutes, and those messages are lost.
Webhook examples in email, SMS and WhatsApp APIs
- Delivery receipts. A send call returns when the provider accepts the message; delivery news comes later. Twilio's status callbacks report
sentorfailed, thendeliveredorundelivered(andreadon WhatsApp). Telnyx sendsmessage.sent, thenmessage.finalized. - Inbound messages. Replies to an SMS gateway number arrive as Telnyx
message.receivedor a request to your Twilio Messaging URL. WhatsApp works the same way; our WhatsApp Cloud API tutorial sets one up. - Bounces and complaints. Telnyx Email sends
email.delivered,email.bouncedandemail.complained; Postmark posts delivery, bounce, spam complaint, open and click events. The transactional email guide covers suppressing bounced addresses. - Verification codes. Bird's Verify events include
verify.verification.verified.
Webhook signature verification: HMAC and public keys
A webhook URL is public, so anyone who finds it can post a fake "delivered" event or an invented reply. A signature over the body proves the request came from the provider, unchanged. With HMAC, the provider hashes the raw body (often with a timestamp and event ID) using a secret you share, and you recompute the hash and compare in constant time. With a public-key signature, you verify with the provider's public key, so no shared secret can leak.
Of the 27 providers in our dataset, 14 sign webhooks (sources checked 23 and 24 September 2026):
| Scheme | Providers |
|---|---|
| HMAC-SHA256 | 360dialog (optional), Bird, Infobip (opt-in, algorithm configurable), Mailgun, Mailtrap, Plivo, Resend, Sinch (optional on Conversation API) |
| HMAC-SHA1 (SHA-256 with your own key, in beta) | Twilio |
| JWT signed with HMAC-SHA256 | Vonage (Messages and Verify APIs) |
| Amazon SNS signature, checked with its X.509 certificate | Amazon SES, AWS End User Messaging |
| ECDSA, opt-in | Twilio SendGrid |
| Ed25519 | Telnyx |
| Not signed | Blip, Botmaker, Brevo, ClickSend, Gupshup, Mailjet, Postmark, SendPulse, SMTP2GO, Textmagic, Treble, WATI, Zenvia |
Check what a scheme covers: Mailgun's HMAC signs only a timestamp and a random token, and Plivo's V2 signature the URL plus a nonce, so neither vouches for the event data. Postmark "does not currently support HMAC webhook signature verification" and recommends Basic auth plus its IP ranges. Each provider card shows its signing status and the page it came from.
Replay protection. A captured delivery can be resent and it still verifies. A signed timestamp lets you refuse old copies, if your code checks it: Bird and Telnyx's Email docs say to reject deliveries more than 5 minutes old, and Mailgun notes that caching its tokens "will prevent replay attacks". Twilio's signature covers no timestamp.
Signing is 7 of the 100 points in our Developer & AI score: full credit with replay protection, 70% for a signature alone, 20% unsigned (methodology; scores in the AI-readiness data).
Verify a webhook signature in Node.js
Bird signs the Standard Webhooks way: HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw body}, keyed with the base64-decoded secret after whsec_, sent as v1,<base64> (two during a secret rotation). Resend sends the same three values as svix- headers.
Illustrative code, written from the official documentation and not run by the editorial team.
import crypto from "node:crypto";
import express from "express";
const app = express();
const key = Buffer.from(process.env.WEBHOOK_SECRET.replace(/^whsec_/, ""), "base64");
app.post("/webhooks/messages", express.raw({ type: "application/json" }), (req, res) => {
const id = req.get("webhook-id");
const ts = req.get("webhook-timestamp") ?? "";
const age = Math.abs(Date.now() / 1000 - Number(ts));
if (!id || !(age <= 300)) return res.sendStatus(400); // missing header or older than 5 minutes
const expected = crypto.createHmac("sha256", key).update(`${id}.${ts}.${req.body}`).digest();
const valid = (req.get("webhook-signature") ?? "").split(" ").some((s) => {
const sig = Buffer.from(s.replace(/^v1,/, ""), "base64");
return sig.length === expected.length && crypto.timingSafeEqual(sig, expected);
});
if (!valid) return res.sendStatus(400);
res.sendStatus(200); // acknowledge first
enqueue(id, req.body); // your job queue; it skips IDs already processed
});
express.raw keeps the exact bytes; re-serialized JSON breaks the signature. In production, prefer the provider's SDK or a Standard Webhooks library; Twilio says "Don't implement your own signature validation."
Handle each webhook event once
Telnyx warns that events "can be concurrent, duplicated, delayed, or delivered out of order." A handler that copes verifies the signature on the raw body, then:
- Stores the event ID under a unique constraint and skips repeats:
webhook-idat Bird (unchanged on retries),data.idat Telnyx, theX-PM-Webhook-Trace-Idheader at Postmark (stable across retries), and at Twilio theI-Twilio-Idempotency-Tokenheader, which Twilio says distinguishes retry attempts. - Answers
2xxat once and does slow work from a queue. - Orders events by their own timestamp: at Bird,
email.deliveredcan arrive beforeemail.accepted.
The sending side of the same problem is an idempotency key. If a provider signs nothing, use what it offers (Basic auth, a URL secret, a static header, IP ranges) and read the status back from the API before acting on an event. The vibe coding security checklist makes this a pre-launch check, and the SMS API tutorial has Twilio and Telnyx handlers in Node.js and Python.
Related guides
- Vibe coding security checklist
- How to send a text message with an API in Node.js and Python
- Transactional email guide
- WhatsApp Business API webhooks
- What is an idempotency key?
About this guide
The PingMyUsers editorial team wrote this entry for developers and AI coding agents wiring delivery, reply and bounce events into an app. Sensaria AG in Switzerland operates the directory; providers don't pay for placement, and none reviewed this page. Report errors, with a source, to contact@sensaria.ch.
Methodology
On 24 September 2026 we re-read the Standard Webhooks specification and every vendor page cited above. The signing table comes from the webhook records of our 27 provider cards. We did not send messages, register endpoints or open accounts, and the code was not run. Section order follows 19 AI-search queries and the questions Google shows for "what is a webhook".
Last updated
24 September 2026: first version. Next re-check: March 2027, or sooner if a listed provider changes its retry or signing rules.
Frequently asked questions
What is the difference between a webhook and an API?
Your code calls an API when it wants something; a webhook is the provider calling your code when something happens. You send messages through the API and hear back through webhooks.
How do I create a webhook?
Write an HTTPS route that accepts POST, verifies the signature and returns 200, then register its URL with the provider. Locally, a tunnel such as ngrok gives you a public URL; Sinch's Conversation API doesn't retry callbacks to ngrok domains.
Are webhooks free?
Receiving them costs only your hosting, but plans can limit them. On 24 September 2026, WATI's Growth plan listed "No Webhooks", Resend's Pro plan included 5 webhook endpoints, and Botmaker billed webhooks at US$0.001 per call.
What are the downsides of using webhooks?
Your endpoint must stay up; events can be lost after the last retry, repeated or out of order; unsigned webhooks can be forged.
What is a webhook secret?
The key a provider uses to sign deliveries to one endpoint. Bird shows its whsec_ secret once, when you create the endpoint. Keep it in a secret manager, never in frontend code, and rotate it if it leaks.
Sources
- Standard Webhooks specification, version 1.0.0 — checked 24 September 2026
- Bird — Webhooks (signing, delivery semantics, replay) — checked 24 September 2026
- Twilio — Webhooks security — checked 24 September 2026
- Twilio — Webhooks connection overrides (timeouts, retries, I-Twilio-Idempotency-Token) — checked 24 September 2026
- Twilio — Outbound message status in status callbacks — checked 24 September 2026
- Twilio — Secure your Express app by validating incoming Twilio requests — checked 24 September 2026
- Telnyx — Receiving messaging webhooks — checked 24 September 2026
- Telnyx — Receiving webhooks (API fundamentals) — checked 24 September 2026
- Telnyx — Email webhooks and events — checked 24 September 2026
- Plivo — Messaging callbacks — checked 24 September 2026
- Plivo — Signature validation (messaging, V2) — checked 24 September 2026
- Resend — Webhook retries and replays — checked 24 September 2026
- Resend — Verify webhooks requests — checked 24 September 2026
- Resend — Pricing — checked 24 September 2026
- Postmark — Webhooks overview (security, retry attempts) — checked 24 September 2026
- SMTP2GO — Webhooks overview (retries and timeout) — checked 24 September 2026
- Sinch — Conversation API callbacks (delivery and retries) — checked 24 September 2026
- Mailgun — Securing webhooks — checked 24 September 2026
- Twilio SendGrid — Event Webhook security features — checked 24 September 2026
- Amazon SNS — Verifying the signatures of Amazon SNS messages — checked 24 September 2026
- Amazon SNS — Verifying message signatures (X.509 certificate steps) — checked 24 September 2026
- Botmaker — Cómo integrar webhooks — checked 24 September 2026
- Botmaker — Precios actualizados (USD add-ons) — checked 24 September 2026
- WATI — Pricing — checked 24 September 2026