# Track File Webhook | AudioDN Docs

> The Track File webhook notifies your application about individual track files as they are created or fail — one file at a time, instead of unpacking the full track payload.

Source: https://audiodeliverynetwork.com/docs/webhooks/track-files/

---

# Track File Webhook

The Track File webhook lets your application react to individual [track files](/docs) as they are produced. Each track file is the result of applying a variant (recipe) to a track. Instead of receiving the full `files[]` array on every [track status change](/docs/webhooks/track-processing), this webhook delivers **one track file at a time** — which is easier to handle when a track has many variants.

#### Configured in the dashboard

The Track File webhook URL is set in your **Settings → Webhook** panel in the dashboard, not via the API. Once a URL is saved, every track file event for your organization is delivered to it. Leave it blank to disable it. This is independent of the [Track Processing](/docs/webhooks/track-processing) and [Collection Sync](/docs/webhooks/collection-sync) webhooks — enable whichever you need.

## When it fires

A track normally produces several track files (one per variant). This webhook fires **once per track file** rather than once per track. Every track file — whether it succeeds or fails — is recorded, so you always get exactly one event per file. Each payload carries a `status` (`success` or `failed`) and a matching `event`:

| Outcome | Event | Status | Meaning |
| --- | --- | --- | --- |
| Successfully created | track\_file.created | success | A track file finished processing and was stored. The upload to storage has already completed, so this event marks the file as available. The file object has file.is\_success = true. |
| Failed | track\_file.failed | failed | A variant failed to process. A file row is still delivered so the mapping stays 1:1, but with file.is\_success = false, no url, and the reason in message. |

-   Sent as an HTTP `POST` with `Content-Type: application/json`.
-   Includes an `X-ADN-Event` header set to the event name (`track_file.created` or `track_file.failed`).
-   Branch on the top-level `status` (`success` / `failed`) or on `file.is_success`.
-   Delivery is fire-and-forget / at-least-once — design your handler to be idempotent (key on `file_id`, or on `track_id` + `variant.index`).
-   Event ordering is not guaranteed across files.
-   Requests are currently unsigned. Treat the webhook URL as a secret and, if needed, verify the `track_id` against the API.
-   Respond promptly with a `2xx` status code to acknowledge receipt.

#### Track File vs Track Processing

Use the [Track Processing webhook](/docs/webhooks/track-processing) to react to a track's overall lifecycle (`processing` → `ready`). Use the Track File webhook when you care about each individual output file as it lands — for example, to unlock a purchased lossless download the moment it is ready, without waiting for the whole track to finish.

## Payload schema

The `file` object matches a single entry of the `files[]` array delivered by the Track Processing webhook, including the nested `variant` (recipe) that produced it, plus `is_success`. Both success and failure deliver a `file` object. On failure, `file.is_success` is `false`, `file.url` is `null` (no object was stored), and the reason is in the top-level `message` (mirrored in `file.status_text`).

```
{
  "event": "track_file.created | track_file.failed",
  "status": "success | failed",
  "organization_id": "uuid",
  "creator_id": "uuid | null",
  "collection_id": "uuid",
  "track_id": "uuid",
  "file_id": "uuid",
  "message": "string | null",
  "file": {
    "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"
      }
    }
  }
}
```

Read the variant that produced (or would have produced) the file from `file.variant`. On success, `message` is `null` and `file.url` points at the stored object. On failure, `message` holds the error, `file.url` is `null`, and `file.size` / `file.content_type` may be `null`.

## Example payloads

### Successfully created

Sent when a track file finishes processing and is stored.

```
{
  "event": "track_file.created",
  "status": "success",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "creator_id": null,
  "collection_id": "22222222-2222-2222-2222-222222222222",
  "track_id": "33333333-3333-3333-3333-333333333333",
  "file_id": "55555555-5555-5555-5555-555555555555",
  "message": null,
  "file": {
    "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"
      }
    }
  }
}
```

### Failed (variant error)

Sent when a variant fails to process. A `file` row is still delivered (so the mapping stays 1:1), but with `is_success: false`, no `url`, and the reason in `message`.

```
{
  "event": "track_file.failed",
  "status": "failed",
  "organization_id": "11111111-1111-1111-1111-111111111111",
  "creator_id": null,
  "collection_id": "22222222-2222-2222-2222-222222222222",
  "track_id": "33333333-3333-3333-3333-333333333333",
  "file_id": "77777777-7777-7777-7777-777777777777",
  "message": "ffmpeg exited with code 1: unsupported sample format",
  "file": {
    "id": "77777777-7777-7777-7777-777777777777",
    "path": "org/collection/track/preview-30s.aac",
    "url": null,
    "size": null,
    "content_type": "audio/aac",
    "file_name": "preview-30s.aac",
    "is_public": false,
    "is_success": false,
    "status_text": "ffmpeg exited with code 1: unsupported sample format",
    "data": null,
    "props": null,
    "variant": {
      "id": "66666666-6666-6666-6666-666666666666",
      "index": "preview-30s",
      "variant_type": {
        "id": "preview",
        "viewer_id": "audio",
        "title": "Preview Clip"
      }
    }
  }
}
```

#### Verifying delivery

Each delivery attempt is logged on AudioDN's side, including the HTTP status code returned by your endpoint. If you stop receiving events, confirm your endpoint returns a `2xx` response quickly and that the Track File webhook URL in Settings is correct.

## Handling webhooks

Branch on `status` (or `file.is_success`). Because delivery is at-least-once and unordered, key your logic on `file_id` (or `track_id` + `file.variant.index`) rather than on receipt order.

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

  const { status, track_id, file, message } = req.body
  if (status === 'success') {
    // A single track file is ready — store or unlock it.
    saveTrackFile(track_id, file)
  } else {
    // A variant failed — file.is_success is false and file.url is null.
    flagVariantFailure(track_id, file.variant, message)
  }
})
```
