https://retellai.com/?utm_source=discord&utm_medium=seo logo
I'm implementing webhook signature verification fo...
# ❓・ai-evy-support
d
@AI Evy I'm implementing webhook signature verification for Retell AI webhooks in Deno/TypeScript. I can see the webhook sends a signature header "x-retell-signature" with format "v=,d=". Can you provide: 1. The exact payload that gets signed (raw body? timestamp+body? something else?) 2. Which secret to use (API key or webhook secret?) 3. A complete code example showing HMAC-SHA256 verification 4. Whether the signature is hex or base64 encoded I've tried signing just the body with both keys but the signatures don't match.
a
Thanks for tagging me @Davis. I'll look through relevant sources and get back to you shortly.
### Answer Here's what the documentation confirms about webhook signature verification: 1. Payload that gets signed: The signed message is
timestamp.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:
Copy code
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:
Copy code
typescript
// 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.
​ To learn more, see the sources I considered: [[1] Webhook Verification](https://discord.com/channels/1186424376300679209/1400483295082451026) [[2] Secure the webhook](https://docs.retellai.com/features/secure-webhook) [[3] Inbound webhook](https://docs.retellai.com/features/inbound-call-webhook) ​
Feel free to tag @AI Evy with additional questions. I also appreciate feedback, it helps me improve.