Zur Navigation springen

Webhooks nach Anrufen

Erhalten Sie über Webhooks Benachrichtigungen, wenn Anrufe enden und die Analyse abgeschlossen ist.

Übersicht

Webhooks nach Anrufen ermöglichen Ihnen, nach Abschluss der Analyse detaillierte Informationen zu einem Anruf zu erhalten. Wenn aktiviert, sendet ElevenLabs eine POST-Anfrage mit umfassenden Anrufdaten an Ihren angegebenen Endpunkt.

ElevenLabs unterstützt drei Arten von Webhooks nach Anrufen:

  • Transkriptions-Webhooks (post_call_transcription): Enthalten vollständige Gesprächsdaten, einschließlich Transkripten, Analyseergebnissen und Metadaten
  • Audio-Webhooks (post_call_audio): Enthalten minimale Daten mit Base64-kodiertem Audio des gesamten Gesprächs
  • Webhooks bei fehlgeschlagener Anrufinitiierung (call_initiation_failure): Enthalten Informationen zu fehlgeschlagenen Anrufinitiierungsversuchen, einschließlich Fehlergründen und Metadaten

Webhooks nach Anrufen aktivieren

Webhooks nach Anrufen können über die Einstellungsseite von ElevenAgents für alle Agents in Ihrem Workspace aktiviert werden.

Einstellungen für Webhooks nach Anrufen

Webhooks nach Anrufen müssen einen Statuscode 200 zurückgeben, um als erfolgreich zu gelten. Webhooks, die wiederholt fehlschlagen, werden automatisch deaktiviert, wenn 10 oder mehr aufeinanderfolgende Fehler auftreten und die letzte erfolgreiche Zustellung mehr als 7 Tage zurückliegt oder noch nie eine erfolgreiche Zustellung erfolgt ist.

Webhooks nach Anrufen können bei Fehlschlägen automatisch erneut versucht werden. Siehe Webhook- Wiederholungen.

Authentifizierung

Der Listener muss alle eingehenden Webhooks validieren. Webhooks unterstützen derzeit die Authentifizierung über HMAC-Signaturen. So richten Sie die HMAC-Authentifizierung ein:

  • Speichern Sie das beim Erstellen des Webhooks generierte gemeinsame Geheimnis sicher.
  • Verifizieren Sie den Header ElevenLabs-Signature in Ihrem Endpunkt mithilfe des SDK.

Das JavaScript-SDK stellt constructEvent bereit, das Python-SDK construct_event mit rawBody, sig_header und secret (diese heißen in Python nicht payload / signature). Beide verifizieren die Signatur, validieren den Zeitstempel und parsen die JSON-Nutzlast.

Beispiel für einen Webhook-Handler mit FastAPI:

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"}

Benutzerdefinierte Request-Header

Zusätzlich zur HMAC-Signaturvalidierung können Sie jeder Webhook-Zustellung benutzerdefinierte Header hinzufügen. Das ist nützlich, um API-Schlüssel, Bearer-Token oder andere Authentifizierungs-Header zu übermitteln, die Ihr empfangender Endpunkt benötigt.

Benutzerdefinierte Header können derzeit nicht über das ElevenAgents-Dashboard konfiguriert werden. Verwenden Sie das SDK oder die API, um benutzerdefinierte Header festzulegen.

Benutzerdefinierte Header funktionieren zusammen mit der HMAC-Authentifizierung. auth_type muss weiterhin auf hmac gesetzt sein, und benutzerdefinierte Header werden zusätzlich zum Header ElevenLabs-Signature gesendet.

Benutzerdefinierte Header sind nur schreibbar. Der Endpunkt zum Auflisten von Webhooks gibt request_headers nicht in seiner Antwort zurück, daher können Sie nicht auslesen, welche Header für einen Webhook konfiguriert sind.

IP-Zulassungslisten

Für zusätzliche Sicherheit können Sie die statischen ausgehenden IP-Adressen von ElevenLabs zu Ihrer Zulassungsliste hinzufügen. Die vollständige Liste der IP-Adressen finden Sie unter IP-Zulassungslisten.

Die Kombination von IP-Zulassungslisten mit HMAC-Signaturvalidierung bietet mehrere Sicherheitsebenen.

Webhook-Überschreibungen pro Agent

Standardmäßig verwenden alle Agents in Ihrem Workspace den Webhook, der in Ihren Workspace-Einstellungen konfiguriert ist. Sie können dies pro Agent überschreiben, um Daten nach Anrufen für verschiedene Agents an unterschiedliche Endpunkte zu senden.

1

Agent-Einstellungen öffnen

Navigieren Sie zu Ihrem Agent im ElevenAgents-Dashboard und öffnen Sie Einstellungen.

2

Webhook-Überschreibung konfigurieren

Wählen Sie im Abschnitt Webhooks nach Anrufen einen anderen Webhook aus der Dropdown-Liste, um den Workspace-Standard für diesen Agent zu überschreiben. Sie können auch konfigurieren, welche Ereignistypen gesendet werden.

Einstellungen für Agent-Webhook-Überschreibungen

post_call_webhook_id muss auf einen Webhook verweisen, der bereits in Ihrem Workspace vorhanden ist. Mit dem Array events können Sie auch festlegen, welche Ereignistypen gesendet werden:

EreignistypBeschreibung
transcriptTranskriptionsdaten mit Gesprächsdetails und Analyse
audioBase64-kodiertes MP3-Audio des gesamten Gesprächs
call_initiation_failureInformationen zu fehlgeschlagenen Anrufinitiierungsversuchen
answering_machine_detectionErgebnisse der Anrufbeantwortererkennung (nur ausgehende Anrufe)
unredacted_transcriptTranskript mit unveränderten personenbezogenen Daten (erfordert entsprechende Datenaufbewahrung)
unredacted_audioAudio ohne Schwärzung personenbezogener Daten (erfordert entsprechende Datenaufbewahrung)

Struktur der Webhook-Antwort

ElevenLabs sendet drei verschiedene Arten von Webhooks nach Anrufen, jeweils mit unterschiedlichen Datenstrukturen:

Transkriptions-Webhooks (post_call_transcription)

Enthalten umfassende Gesprächsdaten, einschließlich vollständiger Transkripte, Analyseergebnisse und Metadaten.

Felder der obersten Ebene

FeldTypBeschreibung
typestringEreignistyp (immer post_call_transcription)
dataobjectGesprächsdaten in der Struktur ConversationHistoryCommonModel
event_timestampnumberZeitpunkt dieses Ereignisses als Unix-Zeit in UTC

Struktur des Datenobjekts

Das Objekt data enthält:

FeldTypBeschreibung
agent_idstringDie ID des Agents, der den Anruf bearbeitet hat
agent_namestringDer Name des Agents zum Zeitpunkt des Gesprächs
conversation_idstringEindeutige Kennung für das Gespräch
statusstringStatus des Gesprächs (z. B. “done”)
user_idstringBenutzerkennung, falls verfügbar
branch_idstringDer für das Gespräch verwendete Agent-Branch, falls zutreffend
version_idstringDie ID der Agent-Version (Snapshot), die während des Anrufs aktiv war
environmentstringDie zum Auflösen von Umgebungsvariablen verwendete Umgebung
transcriptarrayVollständiges Gesprächstranskript mit Gesprächszügen
metadataobjectAnrufzeiten, Kosten und Telefoniedetails
analysisobjectAuswertungsergebnisse und Gesprächszusammenfassung
conversation_initiation_client_dataobjectKonfigurationsüberschreibungen und dynamische Variablen
has_audiobooleanOb für das Gespräch Audio verfügbar ist
has_user_audiobooleanOb Benutzeraudio für das Gespräch verfügbar ist
has_response_audiobooleanOb Agent-Antwortaudio für das Gespräch verfügbar ist

Audio-Webhooks (post_call_audio)

Enthalten minimale Daten mit dem vollständigen Gesprächsaudio als Base64-kodiertes MP3.

Felder der obersten Ebene

FeldTypBeschreibung
typestringEreignistyp (immer post_call_audio)
dataobjectMinimale Audiodaten
event_timestampnumberZeitpunkt dieses Ereignisses als Unix-Zeit in UTC

Struktur des Datenobjekts

Das Objekt data enthält nur:

FeldTypBeschreibung
agent_idstringDie ID des Agents, der den Anruf bearbeitet hat
conversation_idstringEindeutige Kennung für das Gespräch
full_audiostringBase64-kodierter String mit dem vollständigen Gesprächsaudio im MP3-Format

Audio-Webhooks enthalten nur die drei oben aufgeführten Felder. Sie enthalten KEINE Transkriptionsdaten, Metadaten, Analyseergebnisse oder andere Gesprächsdetails.

Webhooks bei fehlgeschlagener Anrufinitiierung (call_initiation_failure)

Enthalten Informationen zu Versuchen, Telefonanrufe zu initiieren, einschließlich Fehlergründen und Metadaten des Telefonieanbieters.

Webhook-Ereignisse bei fehlgeschlagener Anrufinitiierung werden gesendet, wenn ein Anruf aufgrund von Verbindungsfehlern, einer Ablehnung durch den Benutzer oder weil der Benutzer nicht abnimmt, nicht initiiert werden kann. Wenn ein Anruf an die Mailbox geht oder von einem automatisierten Dienst angenommen wird, wird kein Webhook bei fehlgeschlagener Anrufinitiierung gesendet, da der Anruf erfolgreich initiiert wurde.

Felder der obersten Ebene

FeldTypBeschreibung
typestringEreignistyp (immer call_initiation_failure)
dataobjectDaten zur fehlgeschlagenen Anrufinitiierung
event_timestampnumberZeitpunkt dieses Ereignisses als Unix-Zeit in UTC

Struktur des Datenobjekts

Das Objekt data enthält:

FeldTypBeschreibung
agent_idstringDie ID des Agents, der dem Anruf zugewiesen war
conversation_idstringEindeutige Kennung für das Gespräch
failure_reasonstringDer Fehlergrund (“busy”, “no-answer”, “unknown”)
metadataobjectZusätzliche Daten des Telefonieanbieters

Bei über Twilio getätigten ausgehenden Anrufen wird failure_reason aus dem Twilio-CallStatus abgeleitet: busy und no-answer werden unverändert übernommen, failed wird als unknown gemeldet. Andere Twilio-Anrufstatus senden keinen Webhook bei fehlgeschlagener Anrufinitiierung.

Struktur des Metadatenobjekts

Die Struktur des Objekts metadata variiert je nachdem, ob der ausgehende Anruf über Twilio oder über SIP-Trunking getätigt wurde. Das Objekt enthält ein Feld type, das zwischen den beiden unterscheidet, sowie ein Feld body mit anbieterspezifischen Details.

SIP-Metadaten (type: "sip"):

FeldTypErforderlichBeschreibung
typestringJaAnbietertyp (immer sip)
bodyobjectJaSIP-spezifische Informationen zu Anruffehlern

Das Objekt body für SIP-Metadaten enthält:

FeldTypErforderlichBeschreibung
from_numbernumberJaDie Telefonnummer der Partei, die den Anruf initiiert hat.
to_numbernumberJaDie Telefonnummer der angerufenen Partei.
sip_status_codenumberJaSIP-Antwortstatuscode (z. B. 486 für besetzt)
error_reasonstringJaFür Menschen lesbare Fehlerbeschreibung
call_sidstringJaSIP-Anrufsitzungskennung
twirp_codestringNeinTwirp-Fehlercode, falls zutreffend
sip_statusstringNeinDem Statuscode entsprechender SIP-Statustext

Twilio-Metadaten (type: "twilio"):

FeldTypErforderlichBeschreibung
typestringJaAnbietertyp (immer twilio)
bodyobjectJaTwilio-StatusCallback-Body mit Anrufdetails, dokumentiert hier

Beispiel-Webhook-Payloads

Beispiel für einen Transkriptions-Webhook

{
"type": "post_call_transcription",
"event_timestamp": 1739537297,
"data": {
"agent_id": "xyz",
"conversation_id": "abc",
"status": "done",
"user_id": "user123",
"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"
},
"branch_id": null,
"environment": null
}
}
}

Beispiel für einen Audio-Webhook

{
"type": "post_call_audio",
"event_timestamp": 1739537319,
"data": {
"agent_id": "xyz",
"conversation_id": "abc",
"full_audio": "SUQzBAAAAAAA...base64_encoded_mp3_data...AAAAAAAAAA=="
}
}

Beispiele für Webhooks bei fehlgeschlagener Anrufinitiierung

Beispiel für Twilio-Metadaten

{
"type": "call_initiation_failure",
"event_timestamp": 1759931652,
"data": {
"agent_id": "xyz",
"conversation_id": "abc",
"failure_reason": "busy",
"metadata": {
"type": "twilio",
"body": {
"Called": "+441111111111",
"ToState": "",
"CallerCountry": "US",
"Direction": "outbound-api",
"Timestamp": "Wed, 08 Oct 2025 13:54:12 +0000",
"CallbackSource": "call-progress-events",
"SipResponseCode": "487",
"CallerState": "WA",
"ToZip": "",
"SequenceNumber": "2",
"CallSid": "CA8367245817625617832576245724",
"To": "+441111111111",
"CallerZip": "98631",
"ToCountry": "GB",
"CalledZip": "",
"ApiVersion": "2010-04-01",
"CalledCity": "",
"CallStatus": "busy",
"Duration": "0",
"From": "+11111111111",
"CallDuration": "0",
"AccountSid": "AC37682153267845716245762454a",
"CalledCountry": "GB",
"CallerCity": "RAYMOND",
"ToCity": "",
"FromCountry": "US",
"Caller": "+11111111111",
"FromCity": "RAYMOND",
"CalledState": "",
"FromZip": "12345",
"FromState": "WA"
}
}
}
}

Beispiel für SIP-Metadaten

{
"type": "call_initiation_failure",
"event_timestamp": 1759931652,
"data": {
"agent_id": "xyz",
"conversation_id": "abc",
"failure_reason": "busy",
"metadata": {
"type": "sip",
"body": {
"from_number": "+441111111111",
"to_number": "+11111111111",
"sip_status_code": 486,
"error_reason": "INVITE failed: sip status: 486: Busy here (SIP 486)",
"call_sid": "d8e7f6a5-b4c3-4d5e-8f9a-0b1c2d3e4f5a",
"sip_status": "Busy here",
"twirp_code": "unavailable"
}
}
}
}

Zustellung von Audio-Webhooks

Audio-Webhooks werden getrennt von Transkriptions-Webhooks zugestellt und enthalten nur die wesentlichen Felder zur Identifizierung des Gesprächs sowie die Base64-kodierten Audiodaten.

Audio-Webhooks können mit dem Schalter “Audiodaten senden” in Ihren Webhook- Einstellungen aktiviert oder deaktiviert werden. Diese Einstellung kann sowohl auf Workspace-Ebene (in den ElevenAgents-Einstellungen) als auch auf Agent-Ebene (in individuellen Agent-Webhook-Überschreibungen) konfiguriert werden.

Streaming-Zustellung

Audio-Webhooks werden als Streaming-HTTP-Anfragen mit dem Header transfer-encoding: chunked zugestellt, um große Audiodateien effizient zu verarbeiten. Jede Anfrage läuft nach 5 Minuten ab.

Wiederholungen

Wenn Wiederholungen für den Webhook aktiviert sind, werden fehlgeschlagene Audio-Zustellungen nach demselben Zeitplan wie Transkriptions-Webhooks erneut versucht. Bei einer Wiederholung wird die vollständige Audio-Payload erneut gesendet. Deduplizieren Sie daher nach conversation_id. Den Zeitplan, wiederholbare Fehler und Größenlimits für Audio finden Sie unter Webhook-Wiederholungen.

Audio-Webhooks verarbeiten

Da Audio-Webhooks über Chunked Transfer Encoding zugestellt werden, müssen Sie Streaming-Daten korrekt verarbeiten:

import base64
import json
from aiohttp import web
async def handle_webhook(request):
# Check if this is a chunked/streaming request
if request.headers.get("transfer-encoding", "").lower() == "chunked":
# Read streaming data in chunks
chunked_body = bytearray()
while True:
chunk = await request.content.read(8192) # 8KB chunks
if not chunk:
break
chunked_body.extend(chunk)
# Parse the complete payload
request_body = json.loads(chunked_body.decode("utf-8"))
else:
# Handle regular requests
body_bytes = await request.read()
request_body = json.loads(body_bytes.decode('utf-8'))
# Process different webhook types
if request_body["type"] == "post_call_transcription":
# Handle transcription webhook with full conversation data
handle_transcription_webhook(request_body["data"])
elif request_body["type"] == "post_call_audio":
# Handle audio webhook with minimal data
handle_audio_webhook(request_body["data"])
elif request_body["type"] == "call_initiation_failure":
# Handle call initiation failure webhook
handle_call_initiation_failure_webhook(request_body["data"])
return web.json_response({"status": "ok"})
def handle_audio_webhook(data):
# Decode base64 audio data
audio_bytes = base64.b64decode(data["full_audio"])
# Save or process the audio file
conversation_id = data["conversation_id"]
with open(f"conversation_{conversation_id}.mp3", "wb") as f:
f.write(audio_bytes)
def handle_call_initiation_failure_webhook(data):
# Handle call initiation failure events
agent_id = data["agent_id"]
conversation_id = data["conversation_id"]
failure_reason = data.get("failure_reason")
metadata = data.get("metadata", {})
# Log the failure for monitoring
print(f"Call failed for agent {agent_id}, conversation {conversation_id}")
print(f"Failure reason: {failure_reason}")
# Access provider-specific metadata
provider_type = metadata.get("type")
body = metadata.get("body", {})
if provider_type == "sip":
print(f"SIP status code: {body.get('sip_status_code')}")
print(f"Error reason: {body.get('error_reason')}")
elif provider_type == "twilio":
print(f"Twilio CallSid: {body.get('CallSid')}")
print(f"Call status: {body.get('CallStatus')}")
# Update your system with the failure information
# e.g., mark lead as "call_failed" in CRM

Audio-Webhooks können große Dateien sein. Stellen Sie daher sicher, dass Ihr Webhook-Endpunkt Streaming-Anfragen verarbeiten kann und über ausreichend Speicher- bzw. Speicherkapazität verfügt. Das Audio wird im MP3-Format zugestellt.

Anwendungsfälle

Automatisierte Nachbearbeitung von Anrufen

Webhooks nach Anrufen ermöglichen Ihnen, automatisierte Workflows zu erstellen, die unmittelbar nach Ende eines Anrufs ausgelöst werden. Hier sind einige praktische Anwendungen:

CRM-Integration

Aktualisieren Sie Ihr Customer-Relationship-Management-System mit Gesprächsdaten, sobald ein Anruf abgeschlossen ist:

// Example webhook handler
app.post("/webhook/elevenlabs", async (req, res) => {
// HMAC validation code
const { data } = req.body;
// Extract key information
const userId = data.metadata.user_id;
const transcriptSummary = data.analysis.transcript_summary;
const callSuccessful = data.analysis.call_successful;
// Update CRM record
await updateCustomerRecord(userId, {
lastInteraction: new Date(),
conversationSummary: transcriptSummary,
callOutcome: callSuccessful,
fullTranscript: data.transcript,
});
res.status(200).send("Webhook received");
});

Zustandsbehaftete Gespräche

Bewahren Sie den Gesprächskontext über mehrere Interaktionen hinweg, indem Sie den Zustand speichern und abrufen:

  1. Wenn ein Anruf beginnt, übergeben Sie Ihre Benutzer-ID als dynamische Variable.
  2. Wenn ein Anruf endet, richten Sie Ihren Webhook-Endpunkt so ein, dass er Gesprächsdaten anhand der aus dynamic_variables extrahierten Benutzer-ID in Ihrer Datenbank speichert.
  3. Wenn der Benutzer erneut anruft, können Sie diesen Kontext abrufen und ihn als dynamische Variable {{previous_topics}} an das neue Gespräch übergeben.
  4. Dadurch entsteht ein nahtloses Erlebnis, bei dem sich der Agent an frühere Interaktionen “erinnert”.
// Store conversation state when call ends
app.post("/webhook/elevenlabs", async (req, res) => {
// HMAC validation code
const { data } = req.body;
const userId = data.metadata.user_id;
// Store conversation state
await db.userStates.upsert({
userId,
lastConversationId: data.conversation_id,
lastInteractionTimestamp: data.metadata.start_time_unix_secs,
conversationHistory: data.transcript,
previousTopics: extractTopics(data.analysis.transcript_summary),
});
res.status(200).send("Webhook received");
});
// When initiating a new call, retrieve and use the state
async function initiateCall(userId) {
// Get user's conversation state
const userState = await db.userStates.findOne({ userId });
// Start new conversation with context from previous calls
return await elevenlabs.startConversation({
agent_id: "xyz",
conversation_id: generateNewId(),
dynamic_variables: {
user_name: userState.name,
previous_conversation_id: userState.lastConversationId,
previous_topics: userState.previousTopics.join(", "),
},
});
}