Webhooks in Retell AI provide a powerful way to respond to events within your account in real-time. By setting up webhooks, your applications can immediately react to specific actions or changes, enhancing the interactivity and responsiveness of your integrations.

Types of Webhook Events

Currently, Retell AI supports the following webhook event types:

  • call_started: Triggered when a call starts.
  • call_ended: Triggered when a call ends, transferred, or errors out. The event payload includes details like the call transcript, timestamps, and other relevant information.
    • Note you can use disconnection_reason to determine the call’s end reason (hangup, or call transferred, or error).
  • call_analyzed: Triggered when call_analysis object is populated in call return object.

Use Case Example

Consider the call_ended event. This event is triggered when a call in your Retell AI account ends. By listening to this event, you can capture important call details like phone numbers and transcripts and perform custom actions such as logging or data analysis.

Register Webhook

We offer two types of webhooks: Agent-Level and Account-Level, designed to streamline your event notification process. Here’s a brief on each:

Account-level webhooks

Set up through the dashboard’s webhooks tab, these webhooks notify you of events related to any agent under your account. Specify your webhook URL in the dashboard’s webhooks tab to activate.

Agent-level webhooks

When you create the agent, you can set webhook_url field. Any event associated with that agent will be pushed to the agent webhooks url. If set, account level webhooks url will not be triggered for that agent.

Handle Webhook

After registering the webhook, you would want to verify the webhook is from Retell and handle it.

Verifying Webhook

You can secure your server from public network by only allowlisting Retell IP addresses:

You can use the x-retell-signature of the request header together with your Retell API Key to verify the webhook. We have provided verify function in our SDKs to help you with this.

You can also check if IP is from Retell.

The following code snippets demonstrate how to verify and handle the webhook in Node.js and Python.

Sample Code

// install the sdk: https://docs.retellai.com/get-started/sdk
import { Retell } from "retell-sdk";
import express, { Request, Response } from "express";

const app = express();

app.post("/webhook", (req: Request, res: Response) => {
  if (
      req.headers["x-retell-signature"] as string,
  ) {
    console.error("Invalid signature");
  const content = req.body;
  switch (content.event) {
    case "call_started":
      console.log("Call started event received", content.data.call_id);
    case "call_ended":
      console.log("Call ended event received", content.data.call_id);
    case "call_analyzed":
      console.log("Call analyzed event received", content.data.call_id);
      console.log("Received an unknown event:", content.event);
  // Acknowledge the receipt of the event

Sample Payload

The data field in the webhook payload contains the call details. It’s the same content you would receive when you fetch the call details using the get-call API.

  event: 'call_ended',
  data: {
    call_id: '...',
    agent_id: '...',
    audio_websocket_protocol: 'web',
    audio_encoding: 's16le',
    sample_rate: 24000,
    call_status: 'ended',
    start_timestamp: 1714608475945,
    end_timestamp: 1714608491736,
    transcript: '...',
    transcript_object: [ [Object], [Object], [Object], [Object] ],
    transcript_with_tool_calls: [ [Object], [Object], [Object], [Object] ],
    recording_url: '...',
    public_log_url: '...',
    disconnection_reason: 'user_hangup',
    llm_latency: {
      p50: 944.5,
      p90: 959.3,
      p95: 961.15,
      p99: 962.63,
      max: 963,
      min: 926,
      num: 2
    llm_websocket_network_rtt_latency: { num: 0 },
    e2e_latency: {
      p50: 1762.15625,
      p90: 1775.88125,
      p95: 1777.596875,
      p99: 1778.969375,
      max: 1779.3125,
      min: 1745,
      num: 2
    end_call_after_silence_ms: 600000,
    opt_out_sensitive_data_storage: false

Testing Locally

To test webhooks on your local machine, you can use ngrok to generate a production url forwarding requests to your local endpoints.


Choosing to “Opt-Out of Personal and Sensitive Data Storage” means transcripts and recordings post-call won’t be stored.

However, transcripts remain accessible via webhooks, allowing for alternative storage solutions on your end. The recording will also be available in the recording_url field. The link will be accessible for 10 minutes and will be deleted and become inaccessible after 10 minutes.