Hoppa till navigering

Webhooks för Bild och video

Ta emot resultatet av en generering i stället för att polla efter det.

Guide · Förutsätter att du har slutfört snabbstarten för Image & Video .

Översikt

Videogenereringar kan ta flera minuter, vilket gör polling dyrt att hålla öppet. Välj webhook-leverans för en generering så skickar ElevenLabs en flows_generation-händelse till din slutpunkt när genereringen når completed eller failed.

Händelsens payload är det slutliga svaret från motsvarande GET-slutpunkt, så en hanterare som redan förstår polling-svaret behöver ingen separat tolkningsväg.

Innan du börjar

Webhook-leverans använder de webhooks som din arbetsyta har prenumererat på för genereringshändelser. Att konfigurera en kräver två steg: skapa webhooken och prenumerera sedan på händelsen.

1

Skapa en webhook

Gå till Utvecklare > Webhooks och skapa en webhook med en offentligt nåbar HTTPS-callback-URL. Spara signeringshemligheten du får tillbaka; du behöver den för att verifiera inkommande händelser.

2

Prenumerera på genereringshändelser

Under Välj händelser att lyssna på markerar du Image & Video API generation completed. En webhook som finns men inte prenumererar på denna händelse anropas aldrig.

Du kan göra samma sak via API:t genom att skicka händelsen flows till Uppdatera arbetsytans webhook:

{
"events": ["flows"]
}

För att skapa och prenumerera på webhooks krävs behörigheten Webhooks Manage eller att du är arbetsyteadministratör. En enskild händelse kan ha upp till 10 webhooks; därefter misslyckas begäran med too_many_webhooks.

En generering som begär webhook-leverans när ingen webhook prenumererar på genereringshändelser avvisas, så ett resultat genereras aldrig utan någonstans att leverera det.

Begär webhook-leverans

Lägg till ett webhook-objekt i skapa-begäran. Använd {"type": "all"} för att leverera till varje webhook som prenumererar på genereringshändelser, vilket gör begäran stabil när webhooks läggs till eller ersätts.

from elevenlabs import VideoGenerationRequest_Veo31FastGenerate001, WebhookTarget_All
generation = elevenlabs.flows.video.create(
request=VideoGenerationRequest_Veo31FastGenerate001(
prompt="A corgi rides a tiny surfboard across a sunlit wave at golden hour, cinematic",
duration_secs=8,
webhook=WebhookTarget_All(),
)
)

Om du i stället vill rikta in dig på specifika webhooks anger du fältet webhook som en lista med ID:n. Varje ID måste vara en av arbetsytans webhooks som prenumererar på genereringshändelser.

{
"webhook": {
"type": "ids",
"ids": ["Q8mVr2LpXcT4nB6yJdKw"]
}
}

Skapa-begäran validerar målet innan genereringen startar och returnerar ett fel när leverans inte skulle vara möjlig:

FelstatusOrsak
no_webhooks_configuredLeverans till alla webhooks begärdes, men arbetsytan har inga.
invalid_webhook_idEn angiven webhook prenumererar inte på genereringshändelser eller finns inte längre.
webhook_disabledEn riktad webhook är inaktiverad, manuellt eller automatiskt efter fel.

Webhook-leverans fungerar väl med kedjade genereringar: ange webhook för den sista genereringen så körs hela kedjan på serversidan med en enda händelse i slutet. Detta gäller även om kedjan misslyckas halvvägs — felet sprider sig till den sista genereringen, som levererar det som en failed-händelse med orsaken dependency_failed.

Webhook-payload

En slutförd generering levererar utdata-URL:en och MIME-typen:

{
"type": "flows_generation",
"event_timestamp": 1739721600,
"data": {
"id": "JWr5N6X9ZTqf8jD2LmQb",
"status": "completed",
"content_url": "https://storage.googleapis.com/generations/JWr5N6X9ZTqf8jD2LmQb",
"content_mime_type": "video/mp4"
}
}

En misslyckad generering levererar i stället felkategorin och meddelandet:

{
"type": "flows_generation",
"event_timestamp": 1739721600,
"data": {
"id": "JWr5N6X9ZTqf8jD2LmQb",
"status": "failed",
"failure_reason": "timeout",
"error_message": "Timed out while processing. You were not charged for this generation."
}
}

Förgrena på data.status för att avgöra vilka fält som finns. De två slutliga statusarna är de enda som en webhook kan innehålla, eftersom leverans endast sker när en generering är klar.

content_url är en signerad URL som upphör ungefär en timme efter att händelsen skickats. Ladda ned mediet direkt, eller hämta genereringen igen för en ny URL.

Hantera händelsen

En hanterare verifierar signaturen, kontrollerar händelsetypen och förgrenar sedan på data.status. Detta exempel laddar ned utdata från en slutförd generering och loggar orsaken för en misslyckad.

# server.py
import os
import requests
from dotenv import load_dotenv
from elevenlabs.client import ElevenLabs
from elevenlabs.errors import BadRequestError
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
load_dotenv()
app = FastAPI()
elevenlabs = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET")
@app.post("/webhook/flows")
async def receive_generation(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:
return JSONResponse(content={"error": "Invalid signature"}, status_code=401)
# construct_event returns a parsed dict, not an object with attributes.
if event.get("type") != "flows_generation":
return {"status": "ignored"}
generation = event["data"]
if generation["status"] == "completed":
media = requests.get(generation["content_url"]).content
with open(f"{generation['id']}.mp4", "wb") as f:
f.write(media)
else:
print(f"Generation {generation['id']} failed: {generation['failure_reason']}")
return {"status": "received"}

Båda exemplen laddar ned under begäran för korthetens skull. En stor video tar tillräckligt lång tid för att detta kan överskrida leveranstimeouten, så i produktion bör du skicka genererings-ID:t till en kö och returnera 2xx direkt. Den signerade URL:en är giltig i ungefär en timme, vilket räcker gott för en bakgrundsarbetare.

Om du vill ta emot händelser på en lokal server under utveckling kan du exponera den med en tunnel som ngrok och använda HTTPS-URL:en du får som webhookens callback-URL.

Verifiera signaturen

Hanteraren ovan anropar construct_event / constructEvent, som verifierar huvudet ElevenLabs-Signature, validerar tidsstämpeln och tolkar payloaden i ett steg. Verifiera alltid innan du litar på en händelse.

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

Leveransbeteende

Varje generering levererar exakt en slutlig händelse per riktad webhook. Leverans är oberoende av själva genereringen: en webhook som misslyckas eller inte kan nås påverkar inte resultatet, som fortsätter vara tillgängligt från GET-slutpunkten och i listsvar.

Returnera en 2xx-status direkt från din hanterare. Upprepade fel inaktiverar automatiskt en webhook, och en inaktiverad webhook gör att efterföljande genereringar som riktas mot den avvisas vid skapandet. Utforma hanteraren så att den är idempotent och använd genereringens id för att ta bort dubbletter.

För arbetsflöden där ett missat resultat inte är acceptabelt bör du behandla webhooks som den snabba vägen och stämma av regelbundet med flows.image.list eller flows.video.list, filtrerat på status.

Nästa steg