> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Image & Video-Webhooks

> **Note**
>
> **Anleitung** · Setzt voraus, dass Sie den [Image & Video- Schnellstart](/docs/de/eleven-api/guides/cookbooks/image-and-video) abgeschlossen haben.

## Überblick

Videogenerierungen können mehrere Minuten dauern, wodurch fortlaufende Abfragen aufwendig sind. Aktivieren Sie die
Webhook-Zustellung für eine Generierung, und ElevenLabs sendet ein `flows_generation`-Ereignis an Ihren Endpunkt,
sobald die Generierung `completed` oder `failed` erreicht.

Die Ereignis-Payload entspricht der finalen Antwort des zugehörigen GET-Endpunkts. Ein Handler, der
bereits die Abfrageantwort versteht, benötigt daher keinen separaten Parsing-Pfad.

## Bevor Sie beginnen

Die Webhook-Zustellung verwendet die Webhooks, die Ihr Workspace für Generierungsereignisse abonniert hat. Die Einrichtung
besteht aus zwei Schritten: Erstellen Sie den Webhook und abonnieren Sie dann das Ereignis.

#### Webhook erstellen

Öffnen Sie [**Developers** > **Webhooks**](https://elevenlabs.io/app/developers/webhooks) und erstellen Sie einen
Webhook mit einer öffentlich erreichbaren HTTPS-Callback-URL. Bewahren Sie das zurückgegebene Signatur-Secret auf;
Sie benötigen es, um eingehende Ereignisse zu verifizieren.

#### Für Generierungsereignisse abonnieren

Wählen Sie unter **Select events to listen to** die Option **Image & Video API generation or template run
completed** aus. Dasselbe Ereignis übermittelt abgeschlossene [Template-Ausführungen](/docs/de/eleven-api/guides/how-to/templates/run-a-template).
Ein Webhook, der existiert, dieses Ereignis aber nicht abonniert hat, wird nie aufgerufen.

Dasselbe können Sie über die API tun, indem Sie das Ereignis `flows` an
[Workspace-Webhook aktualisieren](/docs/de/api-reference/webhooks/update) übergeben:

```json
{
  "events": ["flows"]
}
```

Zum Erstellen und Abonnieren von Webhooks benötigen Sie die Berechtigung Webhooks Manage oder Workspace-Adminrechte. Ein
Ereignis akzeptiert bis zu 10 Webhooks. Darüber hinaus schlägt die Anfrage mit `too_many_webhooks` fehl.

Eine Generierung, die Webhook-Zustellung anfordert, obwohl kein Webhook für Generierungsereignisse abonniert ist, wird
abgelehnt. So wird nie ein Ergebnis generiert, das nicht zugestellt werden kann.

## Webhook-Zustellung anfordern

Fügen Sie der Erstellungsanfrage ein `webhook`-Objekt hinzu. Verwenden Sie `{"type": "all"}`, um an jeden Webhook
zuzustellen, der Generierungsereignisse abonniert hat. So bleibt die Anfrage stabil, wenn Webhooks hinzugefügt oder ersetzt werden.

```python
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(),
    )
)
```

```typescript
const generation = await elevenlabs.flows.video.create({
  modelId: "veo-3.1-fast-generate-001",
  prompt: "A corgi rides a tiny surfboard across a sunlit wave at golden hour, cinematic",
  durationSecs: 8,
  webhook: { type: "all" },
});
```

Um stattdessen bestimmte Webhooks anzusprechen, setzen Sie das Feld `webhook` auf eine Liste von IDs. Jede ID muss zu
einem Webhook des Workspaces gehören, der Generierungsereignisse abonniert hat.

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

Die Erstellungsanfrage validiert das Ziel vor dem Start der Generierung und gibt einen Fehler zurück, wenn
eine Zustellung nicht möglich wäre:

| Fehlerstatus             | Ursache                                                                                        |
| ------------------------ | ---------------------------------------------------------------------------------------------- |
| `no_webhooks_configured` | Die Zustellung an alle Webhooks wurde angefordert, aber der Workspace hat keine.               |
| `invalid_webhook_id`     | Ein aufgeführter Webhook hat keine Generierungsereignisse abonniert oder existiert nicht mehr. |
| `webhook_disabled`       | Ein adressierter Webhook ist deaktiviert, manuell oder automatisch nach Fehlern.               |

Die Webhook-Zustellung eignet sich gut für [verkettete Generierungen](/docs/de/eleven-api/guides/how-to/image-and-video/references#chain-one-generation-into-the-next):
Setzen Sie `webhook` für die letzte Generierung, und die gesamte Kette läuft serverseitig mit einem einzigen Ereignis am
Ende. Das gilt auch, wenn die Kette mittendrin fehlschlägt — der Fehler wird an die letzte Generierung weitergegeben,
die ihn als `failed`-Ereignis mit dem Grund `dependency_failed` zustellt.

## Webhook-Payload

Eine abgeschlossene Generierung übermittelt die Ausgabe-URL und den MIME-Typ:

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

Eine fehlgeschlagene Generierung übermittelt stattdessen Fehlerkategorie und -meldung:

```json
{
  "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."
  }
}
```

Prüfen Sie `data.status`, um zu entscheiden, welche Felder vorhanden sind. Die beiden finalen Status sind die einzigen,
die ein Webhook enthalten kann, da die Zustellung nur erfolgt, wenn eine Generierung endet.

> **Warning**
>
> `content_url` ist eine signierte URL, die etwa eine Stunde nach dem Senden des Ereignisses abläuft. Laden Sie die
> Mediendatei zeitnah herunter oder rufen Sie die Generierung erneut ab, um eine neue URL zu erhalten.

## Das Ereignis verarbeiten

Ein Handler verifiziert die Signatur, prüft den Ereignistyp und verzweigt dann anhand von `data.status`. Dieses
Beispiel lädt die Ausgabe einer abgeschlossenen Generierung herunter und protokolliert den Grund einer fehlgeschlagenen.

```python maxLines=0
# 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"}
```

```typescript maxLines=0
// server.mts
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";
import express from "express";
import { writeFile } from "fs/promises";

const elevenlabs = new ElevenLabsClient();
const app = express();

const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// The raw body is required: verification runs over the exact bytes sent.
app.post("/webhook/flows", express.raw({ type: "application/json" }), async (req, res) => {
  const signature = req.headers["elevenlabs-signature"] as string;

  let event;
  try {
    event = await elevenlabs.webhooks.constructEvent(
      req.body.toString(),
      signature,
      WEBHOOK_SECRET
    );
  } catch {
    return res.status(401).json({ error: "Invalid signature" });
  }

  if (event.type !== "flows_generation") {
    return res.status(200).json({ received: true });
  }

  const generation = event.data;
  if (generation.status === "completed") {
    const response = await fetch(generation.content_url);
    await writeFile(`${generation.id}.mp4`, Buffer.from(await response.arrayBuffer()));
  } else {
    console.error(`Generation ${generation.id} failed: ${generation.failure_reason}`);
  }

  res.status(200).json({ received: true });
});

app.listen(3000);
```

Beide Beispiele laden der Kürze halber innerhalb der Anfrage herunter. Ein großes Video kann lange genug dauern, um das
Zustellungs-Timeout zu überschreiten. Übergeben Sie die Generierungs-ID daher in der Produktion an eine Queue und geben
Sie sofort 2xx zurück. Die signierte URL ist etwa eine Stunde gültig, was für einen Background Worker ausreichend ist.

> **Tip**
>
> Um während der Entwicklung Ereignisse auf einem lokalen Server zu empfangen, machen Sie ihn über einen Tunnel wie
> [ngrok](https://ngrok.com/) verfügbar und verwenden Sie die bereitgestellte HTTPS-URL als Callback-URL des Webhooks.

## Signatur verifizieren

Der obige Handler ruft `construct_event` / `constructEvent` auf. Dadurch werden der Header
`ElevenLabs-Signature` verifiziert, der Zeitstempel validiert und die Payload in einem Schritt geparst. Verifizieren
Sie immer, bevor Sie einem Ereignis vertrauen.

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.

#### Python

Beispiel für einen Webhook-Handler mit FastAPI:

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

#### JavaScript

#### Express

Beispiel für einen Webhook-Handler mit Express:

```javascript
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';
import express from 'express';

const app = express();

const elevenlabs = new ElevenLabsClient();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// Use express.text() to preserve raw body for signature verification
app.post('/webhook', express.text({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['elevenlabs-signature'];
  const payload = req.body; // Raw string body

  let event;
  try {
    event = await elevenlabs.webhooks.constructEvent(payload, signature, WEBHOOK_SECRET);
  } catch (error) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the webhook event
  if (event.type === 'post_call_transcription') {
    console.log('Received transcription:', event.data);
  }

  res.status(200).json({ received: true });
});
```

#### Next.js

Beispiel für einen Webhook-Handler mit einer Next.js-API-Route:

**`app/api/webhook/route.ts`**

```typescript app/api/webhook/route.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';

const elevenlabs = new ElevenLabsClient();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

export async function POST(req: NextRequest) {
  const body = await req.text();
  const signature = req.headers.get('elevenlabs-signature');

  let event;
  try {
    event = await elevenlabs.webhooks.constructEvent(body, signature, WEBHOOK_SECRET);
  } catch (error) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  // Process the webhook event
  if (event.type === 'post_call_transcription') {
    console.log('Received transcription:', event.data);
  }

  return NextResponse.json({ received: true }, { status: 200 });
}
```

## Zustellungsverhalten

Jede Generierung liefert genau ein finales Ereignis pro adressiertem Webhook. Die Zustellung ist unabhängig von der
Generierung selbst: Ein fehlgeschlagener oder nicht erreichbarer Webhook beeinträchtigt das Ergebnis nicht. Es bleibt
über den GET-Endpunkt und in der Listenantwort verfügbar.

Geben Sie in Ihrem Handler zeitnah einen 2xx-Status zurück. Wiederholte Fehler deaktivieren einen Webhook automatisch,
und ein deaktivierter Webhook führt dazu, dass nachfolgende Generierungen, die ihn adressieren, beim Erstellen abgelehnt
werden. Gestalten Sie den Handler idempotent und verwenden Sie die Generierungs-`id` zur Deduplizierung.

Wenn ein verpasstes Ergebnis nicht akzeptabel ist, behandeln Sie Webhooks als schnellen Pfad und gleichen Sie regelmäßig
mit `flows.image.list` oder `flows.video.list` ab, gefiltert nach `status`.

## Nächste Schritte

#### [Referenzen und Assets](/docs/de/eleven-api/guides/how-to/image-and-video/references)

Steuern Sie eine Generierung mit einer vorherigen Generierung, einem hochgeladenen Asset oder Inline-Medien.

#### [Webhook-Konfiguration](/docs/de/eleven-api/resources/webhooks)

Erstellen, sichern und verwalten Sie Webhooks für Ihren Workspace.

#### [API-Referenz](/docs/de/api-reference/flows/image/create)

Entdecken Sie die Endpunkte für Bilder, Videos und Assets.