# Track-Processing-Webhook | AudioDN Docs

> Der Track-Processing-Webhook informiert Ihre Anwendung, wenn ein Track ein endgültiges Ergebnis erreicht — ready, incomplete oder error — und wenn sein vollständiger Dateisatz abgeschlossen ist.

Source: https://audiodeliverynetwork.com/de/docs/webhooks/track-processing/

---

# Track-Processing-Webhook

Der Track-Processing-Webhook ermöglicht es Ihrer Anwendung, ohne Polling auf das Ergebnis eines Tracks zu reagieren. AudioDN sendet eine HTTP-`POST`\-Anfrage an die für Ihre Organisation konfigurierte Webhook-URL, wenn ein Track einen terminalen Status erreicht oder wenn sein vollständiger Dateisatz abgeschlossen ist. Für Fortschritt auf Dateiebene, während jede Variante erzeugt wird, nutzen Sie stattdessen den [Track-File-Webhook](/docs/webhooks/track-files).

#### Im Dashboard konfiguriert

Die Webhook-URL wird in Ihrem **Settings → Webhook**\-Bereich im Dashboard festgelegt, nicht über die API. Lassen Sie das Feld leer, um Webhooks zu deaktivieren. Für Ereignisse auf Dateiebene siehe den [Track-File-Webhook](/docs/webhooks/track-files), und für Erstellen/Aktualisieren/Löschen-Ereignisse von Sammlungen siehe den [Collection-Sync-Webhook](/docs/webhooks/collection-sync).

## Wann er ausgelöst wird

Um unnötiges Rauschen zu vermeiden, gibt dieser Webhook **keine** Übergangsstatus weiter (`processing`, `fallback`, `fallback_processing`) und auch nicht den anfänglichen Status `initialized`. Er wird nur bei relevanten Ereignissen zugestellt:

-   **Terminaler Status** — der Track erreicht `ready`, `incomplete`, `error` oder `init_error`.
-   **Dateien abgeschlossen** — `track.files_completed_at` wird gesetzt, sobald jede Variante (einschließlich optionaler und nachträglich hinzugefügter) versucht wurde. Dies kann nach einem früheren `ready` eintreten, sodass derselbe Track zweimal zugestellt werden kann: einmal, wenn er abspielbar wird, und einmal, wenn der vollständige Dateisatz fertig ist.

Ein typischer Track wird **einmal** zugestellt (der Status wird zu `ready`, und die Dateien sind im selben Schritt abgeschlossen) oder **zweimal** (frühes `ready` durch erforderliche Varianten, dann ein späteres Ereignis „Dateien abgeschlossen“, sobald optionale Varianten fertig sind).

-   Wird als HTTP-`POST` mit `Content-Type: application/json` gesendet.
-   Enthält einen `X-ADN-Event: track.status_changed`\-Header.
-   Die Zustellung erfolgt nach dem Prinzip „fire-and-forget“ / mindestens einmal — gestalten Sie Ihren Handler idempotent.
-   Die Reihenfolge der Ereignisse ist nicht garantiert; verlassen Sie sich auf die Felder `status`, `previous_status` und `track.files_completed_at` statt auf die Ankunftsreihenfolge.
-   Anfragen sind derzeit unsigniert. Behandeln Sie die Webhook-URL als Geheimnis und prüfen Sie bei Bedarf die `track_id` gegen die API.
-   Antworten Sie zeitnah mit einem `2xx`\-Statuscode, um den Empfang zu bestätigen.

## Track-Statuswerte

Das Feld `status` spiegelt die `track_status_id` des Tracks zum Zeitpunkt des Ereignisses wider. Die möglichen Werte sind:

| Status | Terminal | Bedeutung |
| --- | --- | --- |
| initialized | Nein | Der Track-Datensatz wurde erstellt und wartet darauf, dass der Upload seiner Datei abgeschlossen wird. Dies ist das erste Ereignis, das Sie erhalten. |
| processing | Nein | Der Upload wurde abgeschlossen, und AudioDN transcodiert, erzeugt Wellenformen, extrahiert Metadaten und baut Varianten auf. |
| fallback | Nein | Der primäre Prozessor konnte die Datei nicht verarbeiten, daher wurde sie für den Fallback-Prozessor in die Warteschlange gestellt. |
| fallback\_processing | Nein | Der Fallback-Prozessor bearbeitet den Track aktiv. |
| ready | Ja | Die Verarbeitung wurde erfolgreich abgeschlossen. Alle Track-Dateien sind verfügbar, und der Track ist zur Wiedergabe bereit. |
| incomplete | Ja | Die Verarbeitung wurde mit einem abspielbaren Track abgeschlossen, aber eine oder mehrere nicht essenzielle Varianten sind fehlgeschlagen. Der Track ist nutzbar. |
| error | Ja | Die Verarbeitung ist fehlgeschlagen, und es konnte kein abspielbarer Track erzeugt werden. |
| init\_error | Ja | Der Track konnte nicht initialisiert werden (zum Beispiel war der Upload ungültig oder nicht lesbar). Es fand keine Verarbeitung statt. |

**Terminale** Status (`ready`, `incomplete`, `error`, `init_error`) sind Endzustände — ein Track wechselt seinen Status nicht mehr, sobald er einen davon erreicht hat. Die übrigen Status sind Übergangszustände.

## Payload-Schema

Jedes Ereignis liefert die gleiche Umschlagstruktur. Da Zustellungen auf terminale Ergebnisse und das Ereignis „Dateien abgeschlossen“ beschränkt sind, ist das `files`\-Array normalerweise befüllt. `track.files_completed_at` ist bei einem frühen `ready` `null` (optionale Varianten laufen noch) und ein Zeitstempel, sobald der vollständige Satz fertig ist. Jede Datei enthält `is_success` und ein verschachteltes `variant`\-Objekt (Rezept); eine fehlgeschlagene Variante erscheint mit `is_success: false`, ohne `url`, und mit dem Grund in `status_text`.

```
{
"event": "track.status_changed",
"status": "ready | incomplete | error | init_error",
"previous_status": "string | null",
"organization_id": "uuid",
"creator_id": "uuid | null",
"collection_id": "uuid",
"track_id": "uuid",
"upload_session_id": "uuid | null",
"track": {
  "id": "uuid",
  "track_status_id": "string",
  "upload_session_id": "uuid | null",
  "index": "string",
  "organization_index": "string | null",
  "file_name": "string | null",
  "file_name_original": "string | null",
  "player_title": "string | null",
  "player_subtitle": "string | null",
  "player_color": "string | null",
  "player_color_light": "string | null",
  "player_color_dark": "string | null",
  "order": "number",
  "format": "object | null",
  "metadata": "object | null",
  "duration": "number | null",
  "size": "number | null",
  "files_completed_at": "string | null",
  "cloudflare_image_id": "uuid | null",
  "cover_image": {
    "icon": { "type": "icon", "width": 80, "height": 80, "url": "string" },
    "small": { "type": "small", "width": 200, "height": 200, "url": "string" },
    "regular": { "type": "regular", "width": 400, "height": 400, "url": "string" },
    "large": { "type": "large", "width": 800, "height": 800, "url": "string" }
  },
  "theme": "array | null"
},
"files": [
  {
    "id": "uuid",
    "path": "string",
    "url": "string | null",
    "size": "number | null",
    "content_type": "string | null",
    "file_name": "string",
    "is_public": "boolean",
    "is_success": "boolean",
    "status_text": "string | null",
    "data": "object | null",
    "props": "object | null",
    "variant": {
      "id": "uuid",
      "index": "string",
      "variant_type": {
        "id": "string",
        "viewer_id": "string",
        "title": "string"
      }
    }
  }
]
}
```

## Coverbilder

Wenn ein Track Cover-Artwork besitzt, liefert `track.cover_image` gebrauchsfertige URLs für jede verfügbare Größe, und `track.cloudflare_image_id` speichert die zugrunde liegende Bild-ID, falls Sie später eine URL neu aufbauen müssen. Beide sind `null`, bis ein Cover verfügbar ist (Cover werden während der Verarbeitung extrahiert, sodass frühe Ereignisse wie `initialized` möglicherweise noch keines enthalten).

Bevorzugen Sie die vorgefertigten `cover_image`\-URLs. Wenn Sie nur die Bild-ID aus einem vorherigen Ereignis haben, können Sie jede Größe selbst konstruieren. Jede URL folgt dem unten stehenden Muster, wobei `<variant>` eine der benannten Größen ist:

```
https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/{cloudflare_image_id}/{variant}
```

| Variante | Abmessungen | Beispiel-URL |
| --- | --- | --- |
| icon | 80 x 80 | …/{cloudflare\_image\_id}/icon |
| small | 200 x 200 | …/{cloudflare\_image\_id}/small |
| regular | 400 x 400 | …/{cloudflare\_image\_id}/regular |
| large | 800 x 800 | …/{cloudflare\_image\_id}/large |

Dasselbe Schema gilt für das Cover-Artwork von Sammlungen, das vom [Collection-Sync-Webhook](/docs/webhooks/collection-sync) geliefert wird.

Wenn ein Cover verarbeitet wird, extrahiert ADN daraus auch eine Farbpalette, geliefert als `track.theme` — ein Array von Farbobjekten mit den Werten `hex`, `area`, `lightness` und `saturation` (`null`, bis ein Cover verarbeitet wurde). Dies ist dasselbe `theme`\-Feld, das von der [Tracks-API](/docs/api/tracks) zurückgegeben wird.

## Beispiel-Payloads

### Frühes „ready“ (erforderliche Varianten abgeschlossen)

Wird gesendet, sobald die erforderlichen Varianten erfolgreich sind und der Track abspielbar ist, während optionale Varianten noch verarbeitet werden. `files_completed_at` ist `null`, weil der vollständige Dateisatz noch nicht fertig ist. Ein Track ohne optionale Varianten springt direkt zum unten stehenden abgeschlossenen Ereignis und sendet dieses nie.

```
{
"event": "track.status_changed",
"status": "ready",
"previous_status": "processing",
"organization_id": "11111111-1111-1111-1111-111111111111",
"creator_id": null,
"collection_id": "22222222-2222-2222-2222-222222222222",
"track_id": "33333333-3333-3333-3333-333333333333",
"upload_session_id": "44444444-4444-4444-4444-444444444444",
"track": {
  "id": "33333333-3333-3333-3333-333333333333",
  "track_status_id": "ready",
  "upload_session_id": "44444444-4444-4444-4444-444444444444",
  "index": "track-index-001",
  "organization_index": "your-track-id-001",
  "file_name": "interview.mp3",
  "file_name_original": "Interview Final.mp3",
  "player_title": "Episode 12",
  "player_subtitle": "The Interview",
  "player_color": "#1DB954",
  "player_color_light": "#1BAA4D",
  "player_color_dark": "#1DB954",
  "order": 0,
  "format": { "codec": "aac", "channels": 2, "sample_rate": 44100 },
  "metadata": null,
  "duration": 1832.5,
  "size": 18234123,
  "files_completed_at": null
},
"files": [ { "..." : "playable transcode file(s) so far" } ]
}
```

### „ready“ und Dateien abgeschlossen (endgültig)

Wird gesendet, sobald jede Variante (erforderlich und optional) versucht wurde. `files_completed_at` wird gesetzt, und der vollständige Dateisatz liegt vor. Für einen Track ohne optionale Varianten ist dies die einzige Zustellung, die Sie erhalten.

```
{
"event": "track.status_changed",
"status": "ready",
"previous_status": "processing",
"organization_id": "11111111-1111-1111-1111-111111111111",
"creator_id": null,
"collection_id": "22222222-2222-2222-2222-222222222222",
"track_id": "33333333-3333-3333-3333-333333333333",
"upload_session_id": "44444444-4444-4444-4444-444444444444",
"track": {
  "id": "33333333-3333-3333-3333-333333333333",
  "track_status_id": "ready",
  "upload_session_id": "44444444-4444-4444-4444-444444444444",
  "index": "track-index-001",
  "organization_index": "your-track-id-001",
  "file_name": "interview.mp3",
  "file_name_original": "Interview Final.mp3",
  "player_title": "Episode 12",
  "player_subtitle": "The Interview",
  "player_color": "#1DB954",
  "player_color_light": "#1BAA4D",
  "player_color_dark": "#1DB954",
  "order": 0,
  "format": { "codec": "aac", "channels": 2, "sample_rate": 44100 },
  "metadata": { "artist": "Acme Media" },
  "duration": 1832.5,
  "size": 18234123,
  "files_completed_at": "2026-01-01T12:00:05.000Z",
  "cloudflare_image_id": "77777777-7777-7777-7777-777777777777",
  "cover_image": {
    "icon": { "type": "icon", "width": 80, "height": 80, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/77777777-7777-7777-7777-777777777777/icon" },
    "small": { "type": "small", "width": 200, "height": 200, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/77777777-7777-7777-7777-777777777777/small" },
    "regular": { "type": "regular", "width": 400, "height": 400, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/77777777-7777-7777-7777-777777777777/regular" },
    "large": { "type": "large", "width": 800, "height": 800, "url": "https://imagedelivery.net/iVHDyjXAr_lt5UUJaLbk1Q/77777777-7777-7777-7777-777777777777/large" }
  },
  "theme": [
    { "hex": "#1DB954", "area": 0.42, "lightness": 0.45, "saturation": 0.73 },
    { "hex": "#0E1320", "area": 0.31, "lightness": 0.08, "saturation": 0.35 }
  ]
},
"files": [
  {
    "id": "55555555-5555-5555-5555-555555555555",
    "path": "org/collection/track/transcode.aac",
    "url": "https://cdn.audiodn.com/org/collection/track/transcode.aac",
    "size": 17012344,
    "content_type": "audio/aac",
    "file_name": "transcode.aac",
    "is_public": true,
    "is_success": true,
    "status_text": "OK",
    "data": null,
    "props": null,
    "variant": {
      "id": "66666666-6666-6666-6666-666666666666",
      "index": "transcode-default",
      "variant_type": {
        "id": "transcode",
        "viewer_id": "audio",
        "title": "Transcoded Audio"
      }
    }
  }
]
}
```

### „incomplete“ (teilweiser Erfolg)

Wird gesendet, wenn ein abspielbarer Track erzeugt wurde, aber eine nicht essenzielle Variante fehlgeschlagen ist. Der Track ist weiterhin nutzbar.

```
{
"event": "track.status_changed",
"status": "incomplete",
"previous_status": "processing",
"organization_id": "11111111-1111-1111-1111-111111111111",
"creator_id": null,
"collection_id": "22222222-2222-2222-2222-222222222222",
"track_id": "33333333-3333-3333-3333-333333333333",
"upload_session_id": "44444444-4444-4444-4444-444444444444",
"track": {
  "id": "33333333-3333-3333-3333-333333333333",
  "track_status_id": "incomplete",
  "upload_session_id": "44444444-4444-4444-4444-444444444444",
  "index": "track-index-001",
  "organization_index": "your-track-id-001",
  "file_name": "interview.mp3",
  "file_name_original": "Interview Final.mp3",
  "player_title": "Episode 12",
  "player_subtitle": "The Interview",
  "player_color": "#1DB954",
  "player_color_light": "#1BAA4D",
  "player_color_dark": "#1DB954",
  "order": 0,
  "format": { "codec": "aac", "channels": 2, "sample_rate": 44100 },
  "metadata": null,
  "duration": 1832.5,
  "size": 18234123,
  "files_completed_at": "2026-01-01T12:00:05.000Z"
},
"files": [
  {
    "id": "55555555-5555-5555-5555-555555555555",
    "path": "org/collection/track/transcode.aac",
    "url": "https://cdn.audiodn.com/org/collection/track/transcode.aac",
    "size": 17012344,
    "content_type": "audio/aac",
    "file_name": "transcode.aac",
    "is_public": true,
    "is_success": true,
    "status_text": "OK",
    "data": null,
    "props": null,
    "variant": {
      "id": "66666666-6666-6666-6666-666666666666",
      "index": "transcode-default",
      "variant_type": {
        "id": "transcode",
        "viewer_id": "audio",
        "title": "Transcoded Audio"
      }
    }
  },
  {
    "id": "99999999-9999-9999-9999-999999999999",
    "path": "org/collection/track/lossless.flac",
    "url": null,
    "size": null,
    "content_type": "audio/flac",
    "file_name": "lossless.flac",
    "is_public": false,
    "is_success": false,
    "status_text": "Source is lossy; cannot produce a lossless output",
    "data": null,
    "props": null,
    "variant": {
      "id": "88888888-8888-8888-8888-888888888888",
      "index": "lossless-download",
      "variant_type": {
        "id": "transcode",
        "viewer_id": "audio",
        "title": "Transcoded Audio"
      }
    }
  }
]
}
```

### „error“ (Fehlschlag)

Wird gesendet, wenn die Verarbeitung fehlschlägt und kein abspielbarer Track erzeugt werden konnte. Das `files`\-Array ist leer.

```
{
"event": "track.status_changed",
"status": "error",
"previous_status": "processing",
"organization_id": "11111111-1111-1111-1111-111111111111",
"creator_id": null,
"collection_id": "22222222-2222-2222-2222-222222222222",
"track_id": "33333333-3333-3333-3333-333333333333",
"upload_session_id": "44444444-4444-4444-4444-444444444444",
"track": {
  "id": "33333333-3333-3333-3333-333333333333",
  "track_status_id": "error",
  "upload_session_id": "44444444-4444-4444-4444-444444444444",
  "index": "track-index-001",
  "organization_index": "your-track-id-001",
  "file_name": "interview.mp3",
  "file_name_original": "Interview Final.mp3",
  "player_title": "Episode 12",
  "player_subtitle": "The Interview",
  "player_color": "#1DB954",
  "player_color_light": "#1BAA4D",
  "player_color_dark": "#1DB954",
  "order": 0,
  "format": null,
  "metadata": null,
  "duration": null,
  "size": 18234123,
  "files_completed_at": "2026-01-01T12:00:05.000Z"
},
"files": []
}
```

#### Zustellung überprüfen

Jeder Zustellversuch wird auf Seiten von AudioDN protokolliert, einschließlich des von Ihrem Endpunkt zurückgegebenen HTTP-Statuscodes. Wenn Sie keine Ereignisse mehr erhalten, prüfen Sie, ob Ihr Endpunkt zügig eine `2xx`\-Antwort zurückgibt und ob die Webhook-URL in den Settings korrekt ist.

## Webhooks verarbeiten

Ein minimaler Handler liest das Feld `status` und reagiert auf terminale Zustände. Da die Zustellung mindestens einmal und ungeordnet erfolgt, sollten Sie Ihre Logik auf `track_id` + `status` stützen statt auf die Empfangsreihenfolge.

```
app.post('/webhooks/audiodn', (req, res) => {
// Acknowledge quickly, then process asynchronously.
res.sendStatus(200)

const { event, status, track_id } = req.body
if (event !== 'track.status_changed') return

switch (status) {
  case 'ready':
    // Track is playable. track.files_completed_at === null means optional
    // variants are still running (a second delivery will follow once done).
    markTrackReady(track_id, req.body.files)
    break
  case 'incomplete':
    // Playable, but some variants failed. Inspect files[].is_success.
    markTrackReady(track_id, req.body.files)
    flagForReview(track_id)
    break
  case 'error':
  case 'init_error':
    // Processing failed; no playable track was produced.
    markTrackFailed(track_id)
    break
}
// Note: transitional statuses (processing / fallback*) are not delivered.
// For per-file progress, use the Track File webhook instead.
})
```
