Hoppa till navigering

Webhooks efter samtal

Få meddelanden via webhooks när samtal avslutas och analysen är klar.

Översikt

Webhooks efter samtal gör att du kan få detaljerad information om ett samtal när analysen är klar. När de är aktiverade skickar ElevenLabs en POST-begäran till din angivna slutpunkt med omfattande samtalsdata.

ElevenLabs stöder tre typer av webhooks efter samtal:

  • Webhooks för transkribering (post_call_transcription): Innehåller fullständig konversationsdata, inklusive transkriberingar, analysresultat och metadata
  • Ljudwebhooks (post_call_audio): Innehåller minimala data med base64-kodat ljud från hela konversationen
  • Webhooks för misslyckad samtalsinitiering (call_initiation_failure): Innehåller information om misslyckade försök att initiera samtal, inklusive felorsaker och metadata

Aktivera webhooks efter samtal

Webhooks efter samtal kan aktiveras för alla agenter i din arbetsyta via ElevenAgents inställningssida.

Inställningar för webhook efter samtal

Webhooks efter samtal måste returnera en statuskod på 200 för att räknas som lyckade. Webhooks som misslyckas upprepade gånger inaktiveras automatiskt om det har skett 10 eller fler misslyckanden i följd och den senaste lyckade leveransen var för mer än 7 dagar sedan eller om ingen lyckad leverans någonsin har gjorts.

Webhooks efter samtal kan automatiskt försökas igen om de misslyckas. Se webhook- försök igen.

Autentisering

Det är viktigt att mottagaren validerar alla inkommande webhooks. Webhooks har för närvarande stöd för autentisering via HMAC-signaturer. Konfigurera HMAC-autentisering genom att:

  • Lagra den delade hemligheten som genereras när webhooken skapas på ett säkert sätt
  • Verifiera headern ElevenLabs-Signature i din endpoint med hjälp av SDK:n

JavaScript-SDK:n exponerar constructEvent; Python-SDK:n exponerar construct_event med rawBody, sig_header och secret (dessa heter inte payload / signature i Python). Båda verifierar signaturen, validerar tidsstämpeln och tolkar JSON-payloaden.

Exempel på webhook-hanterare med 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"}

IP-tillåtelselista

För ytterligare säkerhet kan du lägga till ElevenLabs statiska utgående IP-adresser i din tillåtelselista. Se IP-tillåtelselista för den fullständiga listan över IP-adresser.

Att använda IP-tillåtelselista tillsammans med validering av HMAC-signaturer ger flera säkerhetslager.

Webhook-svarstruktur

ElevenLabs skickar tre olika typer av webhookar efter samtal, var och en med olika datastrukturer:

Transkriptionswebhookar (post_call_transcription)

Innehåller omfattande konversationsdata, inklusive fullständiga transkript, analysresultat och metadata.

Fält på toppnivå

FältTypBeskrivning
typestringTyp av händelse (alltid post_call_transcription)
dataobjectKonversationsdata med strukturen ConversationHistoryCommonModel
event_timestampnumberNär händelsen inträffade, i Unix-tid UTC

Datastruktur för objektet

Objektet data innehåller:

FältTypBeskrivning
agent_idstringID för agenten som hanterade samtalet
agent_namestringAgentens namn vid tidpunkten för konversationen
conversation_idstringUnik identifierare för konversationen
statusstringKonversationens status (t.ex. “done”)
user_idstringAnvändaridentifierare, om tillgänglig
branch_idstringAgentgrenen som användes för konversationen, om tillämpligt
version_idstringID för agentversionen (ögonblicksbild) som var aktiv under samtalet
environmentstringMiljön som användes för att lösa miljövariabler
transcriptarrayFullständigt konversationstranskript med turer
metadataobjectTidpunkter för samtal, kostnader och telefonuppgifter
analysisobjectUtvärderingsresultat och konversationssammanfattning
conversation_initiation_client_dataobjectKonfigurationsåsidosättningar och dynamiska variabler
has_audiobooleanOm konversationen har tillgängligt ljud
has_user_audiobooleanOm användarljud är tillgängligt för konversationen
has_response_audiobooleanOm ljud från agentsvaret är tillgängligt för konversationen

Ljudwebhookar (post_call_audio)

Innehåller minimala data med hela konversationsljudet som base64-kodad MP3.

Fält på toppnivå

FältTypBeskrivning
typestringTyp av händelse (alltid post_call_audio)
dataobjectMinimala ljuddata
event_timestampnumberNär händelsen inträffade, i Unix-tid UTC

Datastruktur för objektet

Objektet data innehåller endast:

FältTypBeskrivning
agent_idstringID för agenten som hanterade samtalet
conversation_idstringUnik identifierare för konversationen
full_audiostringBase64-kodad sträng som innehåller hela konversationsljudet i MP3-format

Ljudwebhookar innehåller endast de tre fälten ovan. De innehåller INTE transkriptdata, metadata, analysresultat eller andra konversationsuppgifter.

Webhookar för misslyckad samtalsinitiering (call_initiation_failure)

Innehåller information om försök att initiera telefonsamtal, inklusive orsaker till fel och metadata från telefonioperatören.

Webhookhändelser för misslyckad samtalsinitiering skickas när ett samtal inte kan initieras på grund av anslutningsfel, att användaren avvisar samtalet eller att användaren inte svarar. Om ett samtal går till röstbrevlådan eller besvaras av en automatiserad tjänst skickas ingen webhook för misslyckad samtalsinitiering, eftersom samtalet initierades korrekt.

Fält på toppnivå

FältTypBeskrivning
typestringTyp av händelse (alltid call_initiation_failure)
dataobjectData om misslyckad samtalsinitiering
event_timestampnumberNär händelsen inträffade, i Unix-tid UTC

Datastruktur för objektet

Objektet data innehåller:

FältTypBeskrivning
agent_idstringID för agenten som tilldelades att hantera samtalet
conversation_idstringUnik identifierare för konversationen
failure_reasonstringOrsaken till felet (“busy”, “no-answer”, “unknown”)
metadataobjectYtterligare data från telefonioperatören.

Datastruktur för metadataobjektet

Strukturen för objektet metadata varierar beroende på om det utgående samtalet gjordes via Twilio eller via SIP-trunking. Objektet innehåller fältet type, som skiljer de två åt, och fältet body, som innehåller operatörsspecifika uppgifter.

SIP-metadata (type: "sip"):

FältTypObligatorisktBeskrivning
typestringJaOperatörstyp (alltid sip)
bodyobjectJaSIP-specifik information om samtalsfel

Objektet body för SIP-metadata innehåller:

FältTypObligatorisktBeskrivning
from_numbernumberJaTelefonnummer för parten som initierade samtalet.
to_numbernumberJaTelefonnummer för den uppringda parten.
sip_status_codenumberJaSIP-svarskod (t.ex. 486 för upptaget)
error_reasonstringJaLäsbar felbeskrivning
call_sidstringJaSessionsidentifierare för SIP-samtalet
twirp_codestringNejTwirp-felkod, om tillämpligt
sip_statusstringNejSIP-statustext som motsvarar statuskoden

Twilio-metadata (type: "twilio"):

FältTypObligatorisktBeskrivning
typestringJaOperatörstyp (alltid twilio)
bodyobjectJaTwilio StatusCallback body med samtalsuppgifter, dokumenterat här

Exempel på webhook-payloads

Exempel på transkriptionswebhook

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

Exempel på ljudwebhook

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

Exempel på webhookar för misslyckad samtalsinitiering

Exempel på Twilio-metadata

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

Exempel på SIP-metadata

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

Leverans av ljudwebhookar

Ljudwebhookar levereras separat från transkriptionswebhookar och innehåller endast de nödvändiga fälten för att identifiera konversationen samt base64-kodade ljuddata.

Ljudwebhookar kan aktiveras eller inaktiveras med reglaget “Skicka ljuddata” i dina webhook- inställningar. Den här inställningen kan konfigureras både på arbetsytenivå (i ElevenAgents-inställningarna) och på agentnivå (i enskilda agenters webhook-åsidosättningar).

Strömmande leverans

Ljudwebhookar levereras som strömmande HTTP-begäranden med headern transfer-encoding: chunked för att effektivt hantera stora ljudfiler. Varje begäran får timeout efter 5 minuter.

Återförsök

När återförsök är aktiverade för webhooken görs återförsök för misslyckade ljudleveranser enligt samma schema som för transkriptionswebhookar. Vid ett återförsök skickas hela ljud-payloaden igen, så deduplicera efter conversation_id. Se återförsök för webhookar för schemat, fel som kan återförsökas och gränser för ljudstorlek.

Bearbeta ljudwebhookar

Eftersom ljudwebhookar levereras via chunked transfer encoding behöver du hantera strömmande data korrekt:

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

Ljudwebhookar kan vara stora filer, så se till att din webhook-slutpunkt kan hantera strömmande begäranden och har tillräcklig minnes- och lagringskapacitet. Ljudet levereras i MP3-format.

Användningsområden

Automatiserad uppföljning efter samtal

Webhookar efter samtal gör att du kan bygga automatiserade workflows som utlöses direkt när ett samtal avslutas. Här är några praktiska användningsområden:

CRM-integration

Uppdatera ditt CRM-system med konversationsdata så snart ett samtal avslutas:

// 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");
});

Tillståndsbaserade konversationer

Behåll konversationskontext mellan flera interaktioner genom att lagra och hämta tillstånd:

  1. När ett samtal börjar skickar du med ditt användar-id som en dynamisk variabel.
  2. När ett samtal avslutas konfigurerar du din webhook-slutpunkt för att lagra konversationsdata i din databas, baserat på användar-id:t som extraherats från dynamic_variables.
  3. När användaren ringer igen kan du hämta den här kontexten och skicka den till den nya konversationen i den dynamiska variabeln {{previous_topics}}.
  4. Det skapar en smidig upplevelse där agenten “minns” tidigare interaktioner
// 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(", "),
},
});
}