Davis
12/23/2025, 8:08 PMAI Evy
12/23/2025, 8:08 PMAI Evy
12/23/2025, 8:09 PMtimestamp.rawBody (timestamp + "." + raw JSON body) .
[(1) ]()
2. Which secret to use:
Only the API key that has a webhook badge next to it can be used to verify the webhook. Use the full API key—do not remove the "key_" prefix.
[(2) ]() , [(1) ]()
3. Signature encoding:
The digest (d=) value is hex-encoded (HMAC-SHA256) .
Official SDK approach (Node.js) :
The documentation recommends using the official SDK's Retell.verify() function:
typescript
import { Retell } from "retell-sdk";
import express, { Request, Response } from "express";
const app = express() ;
app.use(express.json() ) ;
app.post("/webhook", (req: Request, res: Response) => {
if (
!Retell.verify(
JSON.stringify(req.body) ,
process.env.RETELL_API_KEY,
req.headers["x-retell-signature"] as string,
)
) {
console.error("Invalid signature") ;
return;
}
const {event, call} = req.body;
// process the webhook
res.status(204) .send() ;
}) ;
[(2) ]()
For Deno/TypeScript without the SDK:
Based on the signature format v=<timestamp>,d=<digest>, the verification logic would be:AI Evy
12/23/2025, 8:09 PMtypescript
// Pseudocode based on documented format
const signatureHeader = request.headers.get("x-retell-signature") ;
const timestamp = signatureHeader.match(/v=(\d+) /) ?.[1];
const providedDigest = signatureHeader.match(/d=([a-f0-9]+) /i) ?.[1];
const message = `${timestamp}.${rawBody}`;
const expectedDigest = hmacSha256Hex(webhookApiKey, message) ;
// Compare expectedDigest with providedDigest
[(1) ]()
Important notes:
- You can also allowlist Retell's IP address: 100.20.5.228
[(2) ]()
- The webhook has a 10-second timeout and retries up to 3 times if no 2xx response is received
[(3) ]()
Since there's no official Deno SDK, you may want to examine the [Node.js SDK source on GitHub]() to see the exact implementation of the verify function.AI Evy
12/23/2025, 8:09 PMAI Evy
12/23/2025, 8:09 PM