Guide to Retell AI Webhooks: Features and Best Practices
Retell AI webhooks notify your application about voice-agent call activity: a call starts, a call ends, a call's analysis completes. If you're building on Retell's voice agents, webhooks are how you react to calls in real time and capture transcripts and outcomes without polling.
This guide covers how Retell webhooks work, the events you'll handle, how to verify the X-Retell-Signature, the retry behavior, and the best practices for production.
What are Retell AI webhooks?
Retell webhooks are HTTP POSTs delivered to a URL you configure (account-level or per-agent), each carrying a call event. Retell signs every delivery with an X-Retell-Signature header. The unusual detail: the signing secret is your Retell API key (the one with a webhook badge), not a separate webhook secret.
Retell AI webhook features
| Feature | Details |
|---|---|
| Configuration | Account-level (dashboard Webhooks tab) or per-agent (webhook_url, overrides account) |
| Signature header | X-Retell-Signature, formatted v={unix_ms_timestamp},d={hex_digest} |
| Signature scheme | HMAC-SHA256 over raw_body + timestamp, keyed with your Retell API key |
| Replay window | ~5 minutes (enforced by the SDK helper) |
| Acknowledgement | 2xx within 10s; retried up to 3 times otherwise |
| IP allowlist | Optional: 100.20.5.228 |
| SDK | retell-sdk (npm, pip) with a verify helper |
Common events
Retell events cover the call lifecycle:
| Event | Fires when |
|---|---|
call_started | A call begins |
call_ended | A call ends |
call_analyzed | Post-call analysis completes |
transcript_updated | The live transcript updates |
There are also chat_* and transfer_* event families. Subscribe to what you process, and consult Retell's webhook reference for the full list.
Setting up Retell webhooks
Configure a webhook at the account level (dashboard Webhooks tab) or per agent (set webhook_url on the agent, which overrides the account-level URL). Optionally allowlist Retell's source IP (100.20.5.228). The signing secret is the Retell API key that carries a webhook badge.
Securing Retell webhooks
Each delivery carries an X-Retell-Signature header formatted v={timestamp},d={hex}, where the digest is an HMAC-SHA256 over raw_body + timestamp, keyed with your Retell API key. Verify against the raw body. The official SDK does this (including the ~5-minute timestamp window and a constant-time comparison), so prefer it over hand-rolling:
const Retell = require("retell-sdk");
const API_KEY = process.env.RETELL_API_KEY; // the key used as the signing secret
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const valid = Retell.verify(
req.body.toString("utf8"), // raw body
API_KEY,
req.headers["x-retell-signature"]
);
if (!valid) return res.sendStatus(401);
res.sendStatus(200); // acknowledge within 10s
processQueue.add(JSON.parse(req.body)); // process asynchronously
});
The same in Python:
import os
from retell import Retell
client = Retell(api_key=os.environ["RETELL_API_KEY"])
@app.post("/webhook")
def webhook():
valid = client.verify(
request.get_data(as_text=True), # raw body
api_key=os.environ["RETELL_API_KEY"],
signature=request.headers["X-Retell-Signature"],
)
if not valid:
return "", 401
# process asynchronously
return "", 200
The exact argument order of the verify helper can vary by SDK version, so follow the current SDK docs. If you verify manually, recompute HMAC-SHA256(api_key, raw_body + timestamp), compare the d= hex in constant time, and reject timestamps outside ~5 minutes.
Retell AI webhook limitations and pain points
The signing secret is your API key
The Problem: Verification uses your Retell API key as the HMAC secret, not a dedicated webhook secret. That couples webhook verification to a broadly-scoped credential, and using the wrong key (or a non-webhook-badged one) fails verification.
Why It Happens: Retell keys webhook signing on the API key rather than issuing a separate secret.
Workarounds:
- Use the API key with the webhook badge, store it securely, and rotate carefully since it's also your API credential.
How Hookdeck Can Help: Hookdeck verifies the X-Retell-Signature at the edge, so the API key lives in one place rather than in every handler.
The signed message is raw_body + timestamp
The Problem: The message appends the timestamp to the raw body (raw_body + timestamp), and the header packs both as v=…,d=…. Signing the body alone, or re-serializing it, fails.
Why It Happens: Retell binds the timestamp into the signature for replay protection.
Workarounds:
- Use the SDK helper, or recompute over
raw_body + timestampand enforce the ~5-minute window yourself.
How Hookdeck Can Help: Hookdeck verifies signature and freshness at the edge, so your app receives pre-verified, fresh events.
Retries and duplicates
The Problem: If your endpoint doesn't 2xx within 10 seconds, Retell retries up to 3 times, so the same event can arrive more than once.
Why It Happens: At-least-once delivery favors eventual delivery of call events.
Workarounds:
- Dedupe on event type +
call_id, and make side effects idempotent.
How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so retries don't double-process calls. See our guide to webhook idempotency.
Account vs agent-level configuration
The Problem: An agent-level webhook_url overrides the account-level one, so events for that agent won't hit your account endpoint. It's easy to miss events if configuration is split.
Why It Happens: Retell lets agents override the account webhook.
Workarounds:
- Track which agents have their own
webhook_urland route consistently.
How Hookdeck Can Help: Hookdeck can receive both account- and agent-level webhooks at one ingestion point and route them uniformly.
Best practices
Verify with the SDK helper
Use retell-sdk's verify with your API key and the raw body; it enforces the ~5-minute window and constant-time comparison. Follow the current SDK docs for argument order.
Acknowledge within 10 seconds, process asynchronously
Return 2xx immediately and defer work to a queue. See why to process webhooks asynchronously.
Dedupe on event + call_id
Use event type + call_id as an idempotency key so retries don't double-process.
Keep account and agent webhooks consistent
Track agent-level webhook_url overrides so you don't miss events.
Make Retell AI webhooks production-ready
Hookdeck verifies X-Retell-Signature, deduplicates, and durably queues every call event
Conclusion
Retell AI webhooks deliver call events verified with an X-Retell-Signature HMAC over raw_body + timestamp, keyed unusually with your Retell API key and packed as v=…,d=…. Use the SDK verify helper, enforce the ~5-minute window, dedupe on call_id, and keep account/agent configuration consistent.
Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique call events.
Get started with Hookdeck for free and handle Retell AI webhooks reliably in minutes.