跳到导航

Webhook

通过接收 webhook 事件启用外部集成。

概览

ElevenLabs 中的某些事件可配置为触发 webhook,让外部应用和系统在事件发生时接收并处理这些事件。目前支持的事件类型包括:

事件类型说明
post_call_transcription智能体平台通话已结束,且分析已完成
voice_removal_notice共享音色计划移除
voice_removal_notice_withdrawn共享音色不再计划移除
voice_removed共享音色已移除,无法再使用
flows_generation图片和视频生成已完成或失败
flows_template_run模板运行已完成或失败

配置

可在通用设置页面创建、禁用和删除 webhook。对于 工作区中的用户,只有工作区管理员可以配置该工作区的 webhook。

HMAC webhook 配置

创建后,可在 智能体平台等产品设置中选择 webhook 来监听事件。

flows_generation 和 flows_template_run 事件都由同一订阅启用:在 选择要监听的事件 下,勾选 图片和视频 API 生成或模板运行已完成,或将 flows 事件传递给更新工作区 webhook。只有创建请求包含 webhook 字段时,生成或运行才会发送事件。

随时可在通用设置页面禁用 webhook。如果 webhook 连续失败 10 次或以上,且上次成功投递已超过 7 天,或从未成功投递,则会被自动禁用。自动禁用的 webhook 需要在设置页面重新启用。不被任何产品使用的 webhook 可以删除。

重试

可为每个 webhook 启用重试,在请求失败时自动再次尝试投递。重试默认禁用。可通过 API 创建或更新 webhook 时启用重试,也可在 webhook 设置中启用。

ElevenAgents 通话后 webhook支持重试,包括转录 (post_call_transcription)、音频(post_call_audio)和通话发起失败 (call_initiation_failure)事件。

重试计划

当投递尝试因可重试错误失败时,系统最多重试 5 次,每次尝试之间的延迟会逐步增加:

尝试次数延迟
1立即
230 秒
32 分钟
48 分钟
530 分钟

每次重试都会加入少量随机抖动(最多为延迟时间的 10%),以分散负载并避免惊群问题。

可重试错误

并非所有失败都会触发重试。只有以下失败被视为可重试:

  • 5xx 状态码(如 500、502、503、504 等服务器错误)。
  • 429(请求过多)。
  • 408(请求超时)。
  • 连接错误和请求超时。

4xx 范围内的请求错误(如 400、401、403、404)不会重试,因为它们通常表示需要手动修正的配置问题。

每个 webhook 的队列限制

每个 webhook 最多可有 100 个待处理的重试任务。如果 webhook 累积超过 100 个排队重试,系统会丢弃新增任务,直到现有重试处理完成。这样可防止单个配置错误的 webhook 占用过多资源。

音频 webhook 还有两项额外限制。大于 50 MiB 的音频负载只会投递一次,不会重试;单个 webhook 的排队音频重试总量不得超过 400 MiB。

自动禁用行为

系统会跟踪每个 webhook 的连续投递失败次数。当同时满足以下条件时,webhook 会自动禁用:

  • 已连续发生 10 次或以上投递失败。
  • webhook 从未成功投递,或上次成功投递已超过 7 天。

当 webhook 被自动禁用时,工作区管理员会收到邮件通知。必须在设置页面手动重新启用 webhook,才能恢复投递。

集成

要集成 webhook,请创建一个端点处理程序,以 POST 请求接收 webhook 事件数据。验证签名后,处理程序应尽快返回 HTTP 200,表示已成功接收。多次未能返回成功响应可能导致 webhook 被自动禁用。

重试负载与原始投递尝试完全相同。webhook 消费方无法仅凭负载区分首次投递和重试,因此请将处理程序设计为幂等——多次处理同一事件应产生相同结果。必要时,可使用 event_timestamp 和事件特定标识符(如 conversation_id)对事件去重。

顶层字段

字段类型说明
typestring事件类型
dataobject事件数据
event_timestampnumber事件发生时间,采用 Unix 时间 UTC

webhook 负载示例

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

音色移除 webhook

当工作区添加的声音库共享音色被其所有者或 ElevenLabs 从声音库中移除时,工作区会收到这些事件。

移除通知(voice_removal_notice)

该音色有通知期。在 future_removal_timestamp 之前仍可使用。

通知期结束时不会发送其他事件。

数据对象结构

字段类型说明
voice_idstring计划移除的音色 ID
future_removal_timestampnumber音色停止可用的时间,采用 Unix 时间 UTC
suggested_voicesarray最多 3 个相似音色。参见推荐音色
{
"type": "voice_removal_notice",
"event_timestamp": 1739537297,
"data": {
"voice_id": "21m00Tcm4TlvDq8ikWAM",
"future_removal_timestamp": 1742129297,
"suggested_voices": [
["https://elevenlabs.io/app/voice-lab/share/a1b2c3d4e5f6/EXAVITQu4vr4xnSDxMaL", "Sarah"]
]
}
}

撤回移除通知(voice_removal_notice_withdrawn)

该音色不再计划移除,且仍可使用。

数据对象结构

字段类型说明
voice_idstring不再移除的音色 ID
{
"type": "voice_removal_notice_withdrawn",
"event_timestamp": 1739537297,
"data": {
"voice_id": "21m00Tcm4TlvDq8ikWAM"
}
}

音色已移除(voice_removed)

该音色未经过通知期便被移除,且无法再使用。

数据对象结构

字段类型说明
voice_idstring已移除音色的 ID
suggested_voicesarray最多 3 个相似音色。参见推荐音色
{
"type": "voice_removed",
"event_timestamp": 1739537297,
"data": {
"voice_id": "21m00Tcm4TlvDq8ikWAM",
"suggested_voices": [
["https://elevenlabs.io/app/voice-lab/share/a1b2c3d4e5f6/EXAVITQu4vr4xnSDxMaL", "Sarah"]
]
}
}

推荐音色

suggested_voices 中的每一项都是含两个元素的数组:先是该音色的声音库分享 URL,后是音色名称。列表可以为空。

身份验证

监听器必须验证所有传入的 webhook。Webhook 目前支持通过 HMAC 签名进行身份验证。可按以下方式设置 HMAC 身份验证:

  • 安全存储创建 webhook 时生成的共享密钥
  • 使用 SDK 在端点中验证 ElevenLabs-Signature 请求头

JavaScript SDK 提供 constructEvent;Python SDK 提供 construct_event,并使用 rawBody、sig_header 和 secret(在 Python 中,它们不叫 payload / signature)。两者都会验证签名、验证时间戳,并解析 JSON 负载。

使用 FastAPI 的 webhook 处理程序示例:

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