> ## Documentation Index
> Fetch the complete documentation index at: https://docs.itellico.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook-Ereignisse

> Referenz für alle Webhook-Ereignistypen, Nutzlasten und Zustellungsverhalten

Webhooks benachrichtigen deine Systeme in Echtzeit, wenn Ereignisse in itellicoAI auftreten.

Abonnements konfigurieren unter **Entwickler → Webhooks**. Siehe [Webhooks](/de/accounts/webhooks) für den UI-Einrichtungsablauf.

Wenn du den Empfänger selbst implementierst, verwende den [Webhook-Implementierungsleitfaden](/de/accounts/webhook-implementation) zusammen mit dieser Referenz.

***

## Ereignistypen

### `conversation.started`

Wird ausgelöst, wenn ein neues Gespräch beginnt (eingehend oder ausgehend).

**Wann es ausgelöst wird:**

* Ein eingehender Anruf wird von einem Agenten entgegengenommen
* Ein ausgehender Kampagnenanruf wird verbunden
* Ein Web- oder Test-Gespräch startet

***

### `conversation.ended`

Wird ausgelöst, wenn ein Gespräch endet.

**Wann es ausgelöst wird:**

* Anruf endet normal (Anrufer oder Agent legt auf)
* Anruf schlägt fehl (Verbindungsfehler, Timeout)
* Anruf wird an ein anderes Ziel weitergeleitet

**Statuswerte in der Nutzlast:**

* `completed`
* `failed`
* `transferred`

***

### `conversation.analysis.completed`

Wird ausgelöst, wenn die gesammelten Insights eines Gesprächs die Verarbeitung abgeschlossen haben.

**Wann es ausgelöst wird:**

* Nach `conversation.ended`, sobald die Zielbewertung und Insight-Verarbeitung abgeschlossen sind

**Enthält:**

* Ergebnisse der Zielanalyse
* Ergebnisse der Post-Call-Analyse
* Serialisierte Gesprächsnachrichten und -ereignisse, die als Analysekontext verwendet werden

<Note>
  Dieses Ereignis wird separat von `conversation.ended` ausgelöst, da die Analyse asynchron nach Gesprächsende läuft. Wenn du sowohl das Gesprächsergebnis als auch die Analysedaten benötigst, abonniere dieses Ereignis.
</Note>

***

## Nutzlastformat

Alle Webhook-Nutzlasten verwenden einen gemeinsamen Umschlag. `data` enthält die ereignisspezifischen Felder.

```json theme={null}
{
  "event_id": "3a8d4e3f-2f36-4cf7-9d4f-2df8e7f6f1c8",
  "event_type": "conversation.ended",
  "created": "2026-04-19T14:30:00.000000+00:00",
  "organization_uuid": "8702eb05-d00c-420d-bbbf-fed4b17b8b64",
  "organization_name": "Acme Support",
  "data": {
    "conversation_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
```

### Beispiel: `conversation.started`

```json theme={null}
{
  "event_id": "3a8d4e3f-2f36-4cf7-9d4f-2df8e7f6f1c8",
  "event_type": "conversation.started",
  "created": "2026-04-19T14:30:00.000000+00:00",
  "organization_uuid": "8702eb05-d00c-420d-bbbf-fed4b17b8b64",
  "organization_name": "Acme Support",
  "data": {
    "conversation_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "agent_uuid": "7b0a1a3d-59c6-46d4-8016-c5ccd5df6864",
    "agent_name": "Concierge",
    "direction": "inbound",
    "channel": "sip",
    "from_number": "+4312345678",
    "to_number": "+43720123456",
    "started_at": "2026-04-19T14:30:00.000Z"
  }
}
```

### Beispiel: `conversation.ended`

```json theme={null}
{
  "event_id": "4c1c44a1-37b8-4d35-b0bc-4d03ad08e601",
  "event_type": "conversation.ended",
  "created": "2026-04-19T14:35:42.000000+00:00",
  "organization_uuid": "8702eb05-d00c-420d-bbbf-fed4b17b8b64",
  "organization_name": "Acme Support",
  "data": {
    "conversation_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "agent_uuid": "7b0a1a3d-59c6-46d4-8016-c5ccd5df6864",
    "agent_name": "Concierge",
    "direction": "inbound",
    "channel": "sip",
    "status": "completed",
    "from_number": "+4312345678",
    "to_number": "+43720123456",
    "started_at": "2026-04-19T14:30:00.000Z",
    "ended_at": "2026-04-19T14:35:42.000Z",
    "duration_seconds": 342,
    "answer_status": "human",
    "messages": [],
    "events": []
  }
}
```

### Beispiel: `conversation.analysis.completed`

```json theme={null}
{
  "event_id": "bb164f3d-c4c7-41a1-8b4e-1abdb7f2d0b2",
  "event_type": "conversation.analysis.completed",
  "created": "2026-04-19T14:36:15.000000+00:00",
  "organization_uuid": "8702eb05-d00c-420d-bbbf-fed4b17b8b64",
  "organization_name": "Acme Support",
  "data": {
    "conversation_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "agent_uuid": "7b0a1a3d-59c6-46d4-8016-c5ccd5df6864",
    "agent_name": "Concierge",
    "analysis_job_uuid": "d86eab3a-142e-43b5-9b0b-c968e30f472d",
    "analyzed_at": "2026-04-19T14:36:15.000Z",
    "model_used": "gpt-4.1-mini",
    "results": {
      "goals": [],
      "post_call": [
        {
          "name": "Customer Satisfaction",
          "type": "rating",
          "value": 4,
          "reasoning": "Caller thanked the agent and expressed appreciation."
        }
      ]
    },
    "messages": [],
    "events": []
  }
}
```

***

## Signaturverifizierung

Wenn du ein Signing-Secret konfiguriert hast, verifiziere die Webhook-Authentizität, indem du eine HMAC-SHA256-Signatur über `<rawBody>.<timestamp>` berechnest.

```python theme={null}
import hmac
import hashlib

def verify_signature(payload_body, timestamp, signature_header, secret):
    signature_base = payload_body + b"." + timestamp.encode()
    expected = hmac.new(
        secret.encode(),
        signature_base,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)
```

```ts theme={null}
import crypto from "node:crypto";

function verifySignature(
  payloadBody: string,
  timestamp: string,
  signatureHeader: string,
  secret: string,
) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${payloadBody}.${timestamp}`)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected, "utf8"),
    Buffer.from(signatureHeader, "utf8"),
  );
}
```

<Warning>
  Vergleiche Signaturen immer mit einer Timing-Safe-Vergleichsfunktion, um Timing-Angriffe zu verhindern.
</Warning>

***

## Ereignisdaten-Felder

### Daten von `conversation.started`

Gemeinsame Felder:

* `conversation_uuid`
* `agent_uuid`, `agent_name`
* `channel`
* `started_at`
* `from_number`, `to_number`
* `ip_address`
* `campaign_uuid`, `campaign_contact_uuid`
* `direction`
* `room_sid`
* `metadata`

### Daten von `conversation.ended`

Enthält alles, was für die Ergebnisverarbeitung benötigt wird:

* `conversation_uuid`
* `agent_uuid`, `agent_name`
* `channel`
* `status`
* `started_at`, `ended_at`, `duration_seconds`
* `from_number`, `to_number`, `ip_address`
* `campaign_uuid`, `campaign_contact_uuid`
* `direction`, `room_sid`
* `metadata`
* `answer_status`
* `messages` (serialisierte Transkriptnachrichten)
* `events` (serialisierte Zeitachsenereignisse)

### Daten von `conversation.analysis.completed`

Enthält Analyseausgabe plus Gesprächskontext:

* `conversation_uuid`
* `agent_uuid`, `agent_name`
* `analysis_job_uuid`
* `analyzed_at`
* `model_used`
* `results.goals`
* `results.post_call`
* `messages`
* `events`

***

## Zustellungs-Header

### Signaturverifizierung

Jede Zustellung enthält Basis-Header:

* `Content-Type: application/json`
* `User-Agent: itellicoAI-Webhook/1.0`
* `X-Webhook-Event-Type`
* `X-Webhook-Version: 1.0`
* `X-Webhook-Event-Id`

Wenn ein Webhook-Secret konfiguriert ist, enthalten Zustellungen zusätzlich:

* `X-Webhook-Timestamp`
* `X-Webhook-Signature-256`

Die Signatur ist HMAC-SHA256 über:

```text theme={null}
<json_payload>.<timestamp>
```

Dabei ist `<json_payload>` der genaue JSON-String, der im Body gesendet wird.

### Verifikations-Pseudocode

```js theme={null}
const expected = hmacSha256Hex(secret, `${rawBody}.${timestamp}`);
const isValid = timingSafeEqual(expected, signatureHeader);
```

Ablehnen, wenn:

* Signatur stimmt nicht überein
* Zeitstempel liegt außerhalb deines Replay-Fensters
* Erforderliche Header fehlen

### Wiederholungslogik

Wenn dein Endpunkt einen Nicht-2xx-Status zurückgibt oder das Timeout überschreitet, werden Zustellungen automatisch wiederholt.

Aktuelles Verhalten:

* maximale Wiederholungen: `5`
* Basis-Wiederholungsverzögerung: `30s`
* Backoff: exponentiell (begrenzt)
* Anfrage-Timeout: `10s`

Inaktive Abonnements werden übersprungen. Zustellungsversuche werden pro Webhook-Abonnement protokolliert.

### Benutzerdefinierte Header

Du kannst benutzerdefinierte Header pro Abonnement für Auth/Routing konfigurieren (zum Beispiel deinen eigenen Bearer-Token-Header).

***

## Nächste Schritte

<CardGroup cols={2}>
  <Card title="Webhooks einrichten" icon="webhook" href="/de/accounts/webhooks">
    Webhook-Abonnements in der Account-UI konfigurieren
  </Card>

  <Card title="Webhook-Implementierungsleitfaden" icon="plug-circle-check" href="/de/accounts/webhook-implementation">
    Den empfangenden Endpunkt erstellen und Ereignisse sicher verarbeiten
  </Card>

  <Card title="Insights sammeln" icon="clipboard-list" href="/de/build/analytics/gather-insights">
    Insights konfigurieren, die `conversation.analysis.completed` auslösen
  </Card>

  <Card title="API-Referenz" icon="brackets-curly" href="/de/api-reference/introduction">
    Vollständige API-Dokumentation anzeigen
  </Card>

  <Card title="Gesprächsziele" icon="bullseye" href="/de/build/analytics/conversation-goals">
    Ziele konfigurieren, die in Analyseereignissen enthalten sind
  </Card>
</CardGroup>
