Track File Webhook
The Track File webhook lets your application react to individual track files 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, this webhook delivers one track file at a time — which is easier to handle when a track has many variants.
Configured in the dashboard
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
POSTwithContent-Type: application/json. - Includes an
X-ADN-Eventheader set to the event name (track_file.createdortrack_file.failed). - Branch on the top-level
status(success/failed) or onfile.is_success. - Delivery is fire-and-forget / at-least-once — design your handler to be idempotent (key on
file_id, or ontrack_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_idagainst the API. - Respond promptly with a
2xxstatus code to acknowledge receipt.
Track File vs Track Processing
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
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)
}
})