# Output Webhook | AudioDN Docs

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

Source: https://audiodeliverynetwork.com/docs/webhooks/outputs/

---

# Output Webhook

The Output webhook lets your application react to individual [outputs](/docs) as they are produced. Each output is the result of applying an output preset to a track. Instead of receiving the full `files[]` array on every [track status change](/docs/webhooks/track-processing), this webhook delivers **one output at a time** — which is easier to handle when a track has many presets. Wire event names remain `track_file.created` and `track_file.failed`.

#### Configured in the dashboard

The Output webhook URL is set in your organization settings in the dashboard, not via the API. Once a URL is saved, every output 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 outputs (one per output preset). This webhook fires **once per output** rather than once per track. Every output — whether it succeeds or fails — is recorded as one logical result (one event type for that output). Delivery is still at-least-once, so handlers must be idempotent. Each payload carries a `status` (`success` or `failed`) and a matching `event`:

| Outcome | Event | Status | Meaning |
| --- | --- | --- | --- |
| Successfully created | track\_file.created | success | An output finished processing and was stored. The upload to storage has already completed, so this event marks the output as available. The file object has file.is\_success = true. Event name remains track\_file.created. |
| Failed | track\_file.failed | failed | An output 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. Event name remains track\_file.failed. |

-   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.

#### Output webhook vs Track Processing

Use the [Track Processing webhook](/docs/webhooks/track-processing) to react to a track’s overall lifecycle (playback-ready, incomplete, error, or files complete). Use the Output webhook when you care about each individual output as it lands — for example, to unlock a purchased lossless download or a WebVTT caption file the moment it is ready. Track-level fields such as `transcription` are only on the Track Processing payload and the Tracks API — not on this per-output event. See also [Voice & transcription](/docs/guides/voice).

## Payload schema

The `file` object matches a single entry of the `files[]` array delivered by the Track Processing webhook, including the nested `variant` object (historical name for the output preset 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 an output 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 Output webhook URL in your organization 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 output 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)
}
})
```
