Zur Navigation springen

Webhooks nach Anrufende

Erhalten Sie per Webhook eine Benachrichtigung, wenn Anrufe enden und die Analyse abgeschlossen ist.

Übersicht

Webhooks nach Anrufende ermöglichen es Ihnen, detaillierte Informationen über einen Anruf zu erhalten, nachdem die Analyse abgeschlossen ist. Wenn sie aktiviert sind, sendet ElevenLabs eine POST-Anfrage mit umfassenden Anrufdaten an Ihren angegebenen Endpunkt.

ElevenLabs unterstützt drei Arten von Webhooks nach Anrufende:

  • 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 vollständigen Gesprächs
  • Webhooks bei fehlgeschlagener Anrufinitiierung (call_initiation_failure): Enthalten Informationen über fehlgeschlagene Anrufinitiierungsversuche, einschließlich Fehlergründen und Metadaten

Webhooks nach Anrufende aktivieren

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

Einstellungen für Webhooks nach Anrufende

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

Webhooks nach Anrufende können bei Fehlern automatisch wiederholt werden. Weitere Informationen finden Sie unter 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 Anfrage-Header

Zusätzlich zur HMAC-Signaturvalidierung können Sie jeder Webhook-Zustellung benutzerdefinierte Header hinzufügen. Dies ist nützlich, um API-Schlüssel, Bearer-Token oder andere Authentifizierungs-Header zu übergeben, 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. Sie können daher nicht auslesen, welche Header für einen Webhook konfiguriert sind.

IP-Zulassungslisten

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

Die Verwendung einer IP-Zulassungsliste zusammen mit der HMAC-Signaturvalidierung bietet mehrere Sicherheitsebenen.

Webhook-Überschreibungen pro Agent

Standardmäßig verwenden alle Agents in Ihrem Workspace den in Ihren Workspace-Einstellungen konfigurierten Webhook. Sie können dies pro Agent überschreiben, um Daten nach Anrufende 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 Anrufende einen anderen Webhook aus der Dropdown-Liste aus, um den Workspace-Standard für diesen Agent zu überschreiben. Sie können auch konfigurieren, welche Ereignistypen gesendet werden sollen.

Einstellungen für Agent-Webhook-Überschreibungen

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

EreignistypBeschreibung
transcriptTranskriptionsdaten mit Gesprächsdetails und Analyse
audioBase64-kodiertes MP3-Audio des vollständigen Gesprächs
call_initiation_failureInformationen über fehlgeschlagene Anrufinitiierungsversuche
answering_machine_detectionErgebnisse der Anrufbeantwortererkennung (nur ausgehende Anrufe)
unredacted_transcriptTranskript mit intakten PII (erfordert angemessene Datenaufbewahrung)
unredacted_audioAudio ohne PII-Schwärzung (erfordert angemessene Datenaufbewahrung)

Struktur der Webhook-Antwort

ElevenLabs sendet drei unterschiedliche Arten von Webhooks nach Anrufende, 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 Umgebung zum Auflösen von Umgebungsvariablen
transcriptarrayVollständiges Gesprächstranskript mit Gesprächszügen
metadataobjectAnrufzeiten, Kosten und Telefondetails
analysisobjectAuswertungsergebnisse und Gesprächszusammenfassung
conversation_initiation_client_dataobjectKonfigurationsüberschreibungen und dynamische Variablen
has_audiobooleanOb Audio für das Gespräch 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
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 Umgebung zum Auflösen von Umgebungsvariablen
full_audiostringBase64-kodierter String mit dem vollständigen Gesprächsaudio im MP3-Format

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

Webhooks bei fehlgeschlagener Anrufinitiierung (call_initiation_failure)

Enthalten Informationen über Versuche zur Initiierung von Telefonanrufen, 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 für die Bearbeitung des Anrufs vorgesehen war
conversation_idstringEindeutige Kennung für das Gespräch
failure_reasonstringDer Fehlergrund (“busy”, “no-answer”, “unknown”)
metadataobjectZusätzliche Daten des Telefonieanbieters

Bei ausgehenden Anrufen über Twilio wird failure_reason vom Twilio-CallStatus abgeleitet: busy und no-answer werden unverändert übernommen, und failed wird als unknown gemeldet. Bei anderen Twilio-Anrufstatus wird kein Webhook bei fehlgeschlagener Anrufinitiierung gesendet.

Struktur des Metadatenobjekts

Die Struktur des Objekts metadata variiert je nachdem, ob der ausgehende Anruf über Twilio oder SIP-Trunking getätigt wurde. Das Objekt enthält ein Feld type, das zwischen 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_sidstringJaSitzungskennung des SIP-Anrufs
twirp_codestringNeinTwirp-Fehlercode, falls zutreffend
sip_statusstringNeinSIP-Statustext zum Statuscode

Twilio-Metadaten (type: "twilio"):

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

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",
"branch_id": "agtbrch_xyz",
"version_id": "agtvrsn_xyz",
"environment": "production",
"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 einzelnen 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 Audiozustellungen nach demselben Zeitplan wie Transkriptions-Webhooks wiederholt. Bei einer Wiederholung wird die vollständige Audio-Payload erneut gesendet. Deduplizieren Sie daher anhand von conversation_id. Informationen zu Zeitplan, wiederholbaren Fehlern und Audiogrößenlimits finden Sie unter Webhook-Wiederholungen.

Audio-Webhooks verarbeiten

Da Audio-Webhooks per 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 ausreichende Speicher- und Speicherkapazität verfügt. Das Audio wird im MP3-Format zugestellt.

Anwendungsfälle

Automatisierte Nachfassaktionen nach Anrufen

Webhooks nach Anrufende ermöglichen Ihnen, automatisierte Workflows zu erstellen, die unmittelbar nach Ende eines Anrufs ausgelöst werden. 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 Status 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 basierend auf 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 vorherige 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(", "),
},
});
}