Skills Development Retell AI Webhook Handling

Retell AI Webhook Handling

v20260311
retellai-webhooks-events
Securely validate Retell AI webhook signatures, route call lifecycle events, and react to transcripts or analysis results so your voice agent integration can log interactions, notify teams, or trigger follow-up actions in real time.
Get Skill
304 downloads
Overview

Retell AI Webhooks & Events

Overview

Handle Retell AI webhooks for real-time voice call lifecycle events. Retell AI fires webhooks when calls start, end, or encounter events during conversation.

Prerequisites

  • Retell AI account with API access
  • Retell AI API key stored in RETELL_API_KEY environment variable
  • HTTPS endpoint for receiving webhook deliveries
  • Voice agent configured in Retell AI dashboard

Webhook Event Types

Event Trigger Payload
call_started AI agent picks up Call ID, agent ID, from/to numbers
call_ended Call completes Call ID, duration, end reason, transcript
call_analyzed Post-call analysis done Sentiment, summary, custom data
agent_transfer Transfer to human Call ID, transfer number, context
voicemail_detected Voicemail reached Call ID, voicemail status
call_error Call fails Error code, error message

Instructions

Step 1: Configure Webhook Endpoint

import express from "express";
import crypto from "crypto";

const app = express();

app.post("/webhooks/retellai",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    const signature = req.headers["x-retell-signature"] as string;
    const secret = process.env.RETELL_WEBHOOK_SECRET!;

    const expected = crypto
      .createHmac("sha256", secret)
      .update(req.body)
      .digest("hex");

    if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
      return res.status(401).json({ error: "Invalid signature" });  # HTTP 401 Unauthorized
    }

    const event = JSON.parse(req.body.toString());
    res.status(200).json({ received: true });  # HTTP 200 OK
    await handleRetellEvent(event);
  }
);

Step 2: Route Call Events

interface RetellWebhookPayload {
  event: string;
  call: {
    call_id: string;
    agent_id: string;
    call_status: string;
    from_number: string;
    to_number: string;
    duration_ms?: number;
    transcript?: string;
    call_analysis?: {
      sentiment: string;
      summary: string;
      custom_analysis_data: Record<string, any>;
    };
  };
}

async function handleRetellEvent(payload: RetellWebhookPayload) {
  switch (payload.event) {
    case "call_started":
      await handleCallStarted(payload.call);
      break;
    case "call_ended":
      await handleCallEnded(payload.call);
      break;
    case "call_analyzed":
      await handleCallAnalyzed(payload.call);
      break;
    case "agent_transfer":
      await handleAgentTransfer(payload.call);
      break;
  }
}

Step 3: Process Call Results

async function handleCallEnded(call: any) {
  const { call_id, duration_ms, transcript, from_number } = call;
  const durationMin = Math.round(duration_ms / 60000);  # 60000: 1 minute in ms

  console.log(`Call ${call_id} ended: ${durationMin}min`);

  await db.calls.create({
    callId: call_id,
    fromNumber: from_number,
    duration: duration_ms,
    transcript,
    completedAt: new Date(),
  });

  if (transcript) {
    await extractActionItems(call_id, transcript);
  }
}

async function handleCallAnalyzed(call: any) {
  const { call_id, call_analysis } = call;
  const { sentiment, summary } = call_analysis;

  if (sentiment === "negative") {
    await alerting.send({
      channel: "#customer-escalations",
      message: `Negative call: ${call_id}\nSummary: ${summary}`,
    });
  }

  await crmClient.logActivity({
    callId: call_id,
    sentiment,
    summary,
  });
}

Step 4: Create Outbound Call via API

set -euo pipefail
curl -X POST https://api.retellai.com/v2/create-phone-call \
  -H "Authorization: Bearer $RETELL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from_number": "+11234567890",  # 11234567890 = configured value
    "to_number": "+10987654321",  # 10987654321 = configured value
    "agent_id": "agt_abc123",
    "webhook_url": "https://api.yourapp.com/webhooks/retellai"
  }'

Error Handling

Issue Cause Solution
Invalid signature Wrong webhook secret Verify secret in Retell AI dashboard
No transcript Short call or error Check end_reason for early termination
Transfer failed Invalid transfer number Verify transfer number is active
Missing analysis Analysis not configured Enable post-call analysis in agent settings

Examples

Post-Call Action Items

async function extractActionItems(callId: string, transcript: string) {
  const items = await llm.extract(transcript, "action_items");
  for (const item of items) {
    await taskManager.createTask({
      title: item,
      source: `Call: ${callId}`,
    });
  }
}

Resources

Next Steps

For deployment setup, see retellai-deploy-integration.

Output

  • Configuration files or code changes applied to the project
  • Validation report confirming correct implementation
  • Summary of changes made and their rationale
Info
Category Development
Name retellai-webhooks-events
Version v20260311
Size 5.59KB
Updated At 2026-03-12
Language