> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Webhooks

## Resumen

Puedes configurar determinados eventos de ElevenLabs para que activen webhooks, lo que permite a aplicaciones y sistemas externos recibir y procesar estos eventos cuando se producen. Los tipos de eventos compatibles actualmente incluyen:

| Tipo de evento                   | Descripción                                                                                                                           |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `post_call_transcription`        | Una llamada de Agents Platform ha terminado y se ha completado el análisis                                                            |
| `voice_removal_notice`           | Está programada la eliminación de una voz compartida                                                                                  |
| `voice_removal_notice_withdrawn` | Ya no está programada la eliminación de una voz compartida                                                                            |
| `voice_removed`                  | Se ha eliminado una voz compartida y ya no se puede usar                                                                              |
| `flows_generation`               | Se ha completado o ha fallado una [generación de Imagen y Video](/docs/es/eleven-api/guides/how-to/image-and-video/webhooks)          |
| `flows_template_run`             | Se ha completado o ha fallado una [ejecución de plantilla](/docs/es/eleven-api/guides/how-to/templates/run-a-template#get-the-result) |

## Configuración

Puedes crear, desactivar y eliminar webhooks desde la página de ajustes generales. Para usuarios de [Espacios de trabajo](/docs/es/overview/administration/workspaces/overview), solo los administradores del espacio de trabajo pueden configurar sus webhooks.

![Configuración de webhook HMAC](/docs/_fern-img/9ea298daac1c64eb43c802a12f7824e83accca44ba2edd1d01a39bcd62c0b9d6.webp)

Después de crearlo, puedes seleccionar el webhook para que escuche eventos en ajustes de productos como [Agents Platform](/docs/es/eleven-agents/workflows/post-call-webhooks).

Los eventos `flows_generation` y `flows_template_run` se activan con una única suscripción: en **Selecciona los eventos que quieres escuchar**, marca **Generación o ejecución de plantilla de la API de Imagen y Video completada**, o envía el evento `flows` a [Actualizar webhook del espacio de trabajo](/docs/es/api-reference/webhooks/update). Una generación o ejecución solo envía su evento si su solicitud de creación incluye un campo `webhook`.

Puedes desactivar los webhooks desde la página de ajustes generales en cualquier momento. Los webhooks que fallan repetidamente se desactivan automáticamente si hay 10 o más fallos consecutivos y la última entrega correcta se realizó hace más de 7 días, o nunca se ha entregado correctamente. Los webhooks desactivados automáticamente deben volver a activarse desde la página de ajustes. Puedes eliminar webhooks si ningún producto los utiliza.

## Reintentos

Puedes activar los reintentos de webhook para cada webhook, de modo que se vuelva a intentar la entrega automáticamente cuando falle una solicitud. Los reintentos están desactivados de forma predeterminada. Actívalos al crear o actualizar un webhook mediante la [API](/docs/es/api-reference/webhooks/create) o en los ajustes del webhook.

> **Note**
>
> Los reintentos son compatibles con los [webhooks posteriores a la llamada ](/docs/es/eleven-agents/workflows/post-call-webhooks) de ElevenAgents, incluidos los eventos de transcripción
> (`post_call_transcription`), audio (`post_call_audio`) y fallo al iniciar la llamada
> (`call_initiation_failure`).

### Calendario de reintentos

Cuando un intento de entrega falla con un error que permite reintento, el sistema lo vuelve a intentar hasta 5 veces, con retrasos crecientes entre intentos:

| Intento | Retraso     |
| ------- | ----------- |
| 1       | Inmediato   |
| 2       | 30 segundos |
| 3       | 2 minutos   |
| 4       | 8 minutos   |
| 5       | 30 minutos  |

Se añade una pequeña variación aleatoria (de hasta el 10 % del retraso) a cada reintento para distribuir la carga y evitar problemas de avalanchas de solicitudes.

### Errores que permiten reintento

No todos los fallos activan un reintento. Solo se consideran reintentables los siguientes fallos:

* Códigos de estado `5xx` (errores de servidor como 500, 502, 503, 504).
* `429` (demasiadas solicitudes).
* `408` (tiempo de espera de la solicitud).
* Errores de conexión y tiempos de espera de solicitudes.

Los errores de solicitud del rango `4xx` (como 400, 401, 403, 404) **no** se reintentan, ya que normalmente indican un problema de configuración que requiere corrección manual.

### Límites de cola por webhook

Cada webhook está limitado a 100 tareas de reintento pendientes. Si un webhook acumula más de 100 reintentos en cola, se descartan las tareas adicionales hasta que se procesen los reintentos existentes. Esto evita que un único webhook mal configurado consuma recursos excesivos.

Los webhooks de audio tienen dos límites adicionales. Una carga útil de audio superior a 50 MiB se entrega una vez y no se vuelve a intentar, y los reintentos de audio en cola de un solo webhook no pueden superar 400 MiB en total.

### Comportamiento de desactivación automática

El sistema registra los fallos de entrega consecutivos de cada webhook. Un webhook se desactiva automáticamente cuando se cumplen ambas condiciones siguientes:

* Se han producido 10 o más fallos de entrega consecutivos.
* El webhook nunca se ha entregado correctamente o la última entrega correcta se realizó hace más de 7 días.

Cuando un webhook se desactiva automáticamente, los administradores del espacio de trabajo reciben una notificación por correo electrónico. Debes volver a activar manualmente el webhook desde la página de ajustes antes de que reanude las entregas.

## Integración

Para integrar webhooks, crea un controlador de ruta que reciba los datos de eventos de webhook como solicitudes POST. Tras validar la firma, el controlador debe devolver HTTP 200 rápidamente para indicar que se ha recibido correctamente. No devolver repetidamente una respuesta correcta puede provocar que el webhook se desactive automáticamente.

La carga útil del reintento es idéntica a la del intento de entrega original. Los consumidores de webhooks no pueden distinguir entre una entrega inicial y un reintento solo a partir de la carga útil, así que diseña tu controlador para que sea **idempotente**: procesar el mismo evento varias veces debe producir el mismo resultado. Usa `event_timestamp` e identificadores específicos del evento (como `conversation_id`) para eliminar eventos duplicados si es necesario.

### Campos de nivel superior

| Campo             | Tipo   | Descripción                |
| ----------------- | ------ | -------------------------- |
| `type`            | string | Tipo de evento             |
| `data`            | object | Datos del evento           |
| `event_timestamp` | string | Cuándo ocurrió este evento |

## Ejemplo de carga útil de webhook

```json
{
  "type": "post_call_transcription",
  "event_timestamp": 1739537297,
  "data": {
    "agent_id": "xyz",
    "conversation_id": "abc",
    "status": "done",
    "transcript": [
      {
        "role": "agent",
        "message": "Hey there angelo. How are you?",
        "tool_calls": null,
        "tool_results": null,
        "feedback": null,
        "time_in_call_secs": 0,
        "conversation_turn_metrics": null
      },
      {
        "role": "user",
        "message": "Hey, can you tell me, like, a fun fact about 11 Labs?",
        "tool_calls": null,
        "tool_results": null,
        "feedback": null,
        "time_in_call_secs": 2,
        "conversation_turn_metrics": null
      },
      {
        "role": "agent",
        "message": "I do not have access to fun facts about Eleven Labs. However, I can share some general information about the company. Eleven Labs is an AI voice technology platform that specializes in voice cloning and text-to-speech...",
        "tool_calls": null,
        "tool_results": null,
        "feedback": null,
        "time_in_call_secs": 9,
        "conversation_turn_metrics": {
          "convai_llm_service_ttfb": {
            "elapsed_time": 0.3704247010173276
          },
          "convai_llm_service_ttf_sentence": {
            "elapsed_time": 0.5551181449554861
          }
        }
      }
    ],
    "metadata": {
      "start_time_unix_secs": 1739537297,
      "call_duration_secs": 22,
      "cost": 296,
      "deletion_settings": {
        "deletion_time_unix_secs": 1802609320,
        "deleted_logs_at_time_unix_secs": null,
        "deleted_audio_at_time_unix_secs": null,
        "deleted_transcript_at_time_unix_secs": null,
        "delete_transcript_and_pii": true,
        "delete_audio": true
      },
      "feedback": {
        "overall_score": null,
        "likes": 0,
        "dislikes": 0
      },
      "authorization_method": "authorization_header",
      "charging": {
        "dev_discount": true
      },
      "termination_reason": ""
    },
    "analysis": {
      "evaluation_criteria_results": {},
      "data_collection_results": {},
      "call_successful": "success",
      "transcript_summary": "The conversation begins with the agent asking how Angelo is, but Angelo redirects the conversation by requesting a fun fact about 11 Labs. The agent acknowledges they don't have specific fun facts about Eleven Labs but offers to provide general information about the company. They briefly describe Eleven Labs as an AI voice technology platform specializing in voice cloning and text-to-speech technology. The conversation is brief and informational, with the agent adapting to the user's request despite not having the exact information asked for."
    },
    "conversation_initiation_client_data": {
      "conversation_config_override": {
        "agent": {
          "prompt": null,
          "first_message": null,
          "language": "en"
        },
        "tts": {
          "voice_id": null
        }
      },
      "custom_llm_extra_body": {},
      "dynamic_variables": {
        "user_name": "angelo"
      }
    }
  }
}
```

## Autenticación

Es importante que el listener valide todos los webhooks entrantes. Actualmente, los webhooks admiten autenticación mediante firmas HMAC. Configura la autenticación HMAC de esta forma:

* Almacena de forma segura el secreto compartido generado al crear el webhook
* Verifica la cabecera ElevenLabs-Signature en tu ruta de API mediante el SDK

El SDK de JavaScript incluye `constructEvent`; el SDK de Python incluye `construct_event` con **`rawBody`**, **`sig_header`** y **`secret`** (en Python no se llaman `payload` / `signature`). Ambos verifican la firma, validan la marca de tiempo y analizan la carga útil JSON.

#### Python

Ejemplo de controlador de webhook con FastAPI:

```python
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from elevenlabs.client import ElevenLabs
from elevenlabs.errors import BadRequestError
import os

load_dotenv()

app = FastAPI()
elevenlabs = ElevenLabs(
    api_key=os.getenv("ELEVENLABS_API_KEY"),
)

WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET")

@app.post("/webhook")
async def receive_message(request: Request):
    payload = await request.body()
    signature = request.headers.get("elevenlabs-signature")

    try:
        event = elevenlabs.webhooks.construct_event(
            rawBody=payload.decode("utf-8"),
            sig_header=signature,
            secret=WEBHOOK_SECRET,
        )
    except BadRequestError as e:
        return JSONResponse(content={"error": "Invalid signature"}, status_code=401)

    # construct_event returns a dict (parsed JSON), not an object with attributes
    if event.get("type") == "post_call_transcription":
        print(f"Received transcription: {event.get('data')}")

    return {"status": "received"}
```

#### JavaScript

#### Express

Ejemplo de controlador de webhook con Express:

```javascript
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';
import express from 'express';

const app = express();

const elevenlabs = new ElevenLabsClient();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// Use express.text() to preserve raw body for signature verification
app.post('/webhook', express.text({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['elevenlabs-signature'];
  const payload = req.body; // Raw string body

  let event;
  try {
    event = await elevenlabs.webhooks.constructEvent(payload, signature, WEBHOOK_SECRET);
  } catch (error) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the webhook event
  if (event.type === 'post_call_transcription') {
    console.log('Received transcription:', event.data);
  }

  res.status(200).json({ received: true });
});
```

#### Next.js

Ejemplo de controlador de webhook con una ruta de API de Next.js:

**`app/api/webhook/route.ts`**

```typescript app/api/webhook/route.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';

const elevenlabs = new ElevenLabsClient();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

export async function POST(req: NextRequest) {
  const body = await req.text();
  const signature = req.headers.get('elevenlabs-signature');

  let event;
  try {
    event = await elevenlabs.webhooks.constructEvent(body, signature, WEBHOOK_SECRET);
  } catch (error) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  // Process the webhook event
  if (event.type === 'post_call_transcription') {
    console.log('Received transcription:', event.data);
  }

  return NextResponse.json({ received: true }, { status: 200 });
}
```