# Lifecycle and files

> Track progress and manage your files.

Use the ID returned when you create a transcode to [check its progress](/docs/api-reference/transcodings/get-transcoding). You can also receive a verified webhook when it is ready, fails, is cancelled, expires, or is deleted.

## Status and progress

| Status | Meaning |
| --- | --- |
| `preparing` | Accepted and being processed. |
| `ready` | The output passed validation and was published; `files` contains the result. |
| `failed` | Processing ended without a published result; inspect `error`. |
| `cancelled` | The request was cancelled. |
| `expired` | The output was in Chunkify temporary storage and its files are no longer available. |

While the status is `preparing`, `processing_stage` shows what is happening:

| Stage | Meaning |
| --- | --- |
| `queued` | Waiting for processing capacity. |
| `starting` | Capacity is reserved and processing is starting. |
| `encoding` | Encoding the output. |
| `finalizing` | Assembling the encoded output. |
| `uploading` | Uploading the output to your storage. |

Video `progress` describes encoding, and reaches 100 only after publication. Encoding can finish before finalization and upload are complete.

Audio-only exports omit video encoding progress. Follow their status and stage instead. Treat `ready` as the signal that the file is available.

## Read a transcode

Replace the example ID with your saved transcode ID. Run these calls on your server with the [official SDK](/docs/integration/sdk) and a Project access token.

<ignore>
SDK publication check: verify Transcodings retrieve/Get signatures and response unwrapping after adding the new resource to the owning SDK generator mappings.
</ignore>

<codegroup>
<codeblock lang="TypeScript">
```typescript
import Chunkify from '@chunkify/chunkify';

async function main() {
    const client = new Chunkify({
        projectAccessToken: 'My Project Access Token',
    });
    const transcoding = await client.transcodings.retrieve(
        'tcg_2G6MJiNz71bHQGNzGwKx5cJwPFS',
    );

    console.log(transcoding.status);
    for (const file of transcoding.files) {
        console.log(file.path, file.size);
    }
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});
```
</codeblock>
<codeblock lang="Python">
```python
from chunkify import Chunkify

client = Chunkify(
    project_access_token="My Project Access Token",
)
transcoding = client.transcodings.retrieve(
    "tcg_2G6MJiNz71bHQGNzGwKx5cJwPFS",
)

print(transcoding.status)
for file in transcoding.files:
    print(file.path, file.size)
```
</codeblock>
<codeblock lang="PHP">
```php
<?php

use Chunkify\Client;

require_once __DIR__ . '/vendor/autoload.php';

$client = new Client(
    projectAccessToken: 'My Project Access Token',
);
$transcoding = $client->transcodings->retrieve(
    'tcg_2G6MJiNz71bHQGNzGwKx5cJwPFS',
);

var_dump($transcoding->status);
foreach ($transcoding->files as $file) {
    var_dump($file->path, $file->size);
}
```
</codeblock>
<codeblock lang="Go">
```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/chunkifydev/chunkify-go"
	"github.com/chunkifydev/chunkify-go/option"
)

func main() {
	client := chunkify.NewClient(
		option.WithProjectAccessToken("My Project Access Token"),
	)
	transcoding, err := client.Transcodings.Get(
		context.Background(),
		"tcg_2G6MJiNz71bHQGNzGwKx5cJwPFS",
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(transcoding.Status)
	for _, file := range transcoding.Files {
		fmt.Println(file.Path, file.Size)
	}
}
```
</codeblock>
</codegroup>

Use [List transcodes](/docs/api-reference/transcodings/list-transcodings) to find requests by ID, Source, output storage, status, or creation time. List and detail responses use the same transcode resource schema.

## Receive lifecycle events

[Set up your webhook and verify signatures](/docs/integration/webhooks) before trusting a notification. Each event contains a saved resource snapshot in `data.transcoding`.

| Event | Meaning |
| --- | --- |
| `transcoding.created` | The request was accepted. |
| `transcoding.ready` | Validated output was published. |
| `transcoding.failed` | Processing failed. |
| `transcoding.cancelled` | The request was cancelled. |
| `transcoding.expired` | Temporary output files expired. |
| `transcoding.deleted` | The record was deleted, by you or on its scheduled `delete_at`. |

Webhooks can arrive more than once or out of order. Store the transcode ID with your application record and retrieve current state when reconciling notifications.

## Use the published files

`files` is empty until publication. Each file includes its ID, output storage and path, size, duration, and measured video or audio properties. Audio-only files omit video properties.

The response's `format` describes the accepted settings; file properties describe what was produced. Per-title requests keep `per_title: true` in `format` without reporting one predicted bitrate for the entire video.

A file's `url` is a signed download valid for at most ten minutes. Retrieve the transcode again for a fresh URL while the file remains available. Signing failures can omit this URL without changing a ready transcode's status.

A configured storage CDN supplies `cdn_url`. Use that URL for lasting delivery from your storage. The file's `path` is relative to the storage prefix saved when the transcode was created.

Video files can also have optional dashboard thumbnails. A thumbnail failure does not fail the media export. Follow [Generate thumbnails](/docs/thumbnails/quickstart) when your application needs generated images or sprites.

## Handle failure and cancellation

For a failed request, `error.stage`, `error.code`, and `error.message` describe the failure. Correct the input or settings and create another transcode when needed. A transcode that hasn't finished within your team's data retention period fails with the `processing_deadline` code and is then deleted.

[Cancel a transcode](/docs/api-reference/transcodings/cancel-transcoding) cancels an unfinished request.

Cancellation is idempotent for an already cancelled request. It returns a conflict once processing is terminal or final publication has started.

Stopping processing can take time after cancellation is accepted. If deletion reports that processing is still stopping, retry deletion later.

## Expiry and deletion

Outputs in Chunkify temporary storage expire 24 hours after publication, as shown by `expires_at`. The transcode then becomes `expired`: its files no longer have usable download or CDN URLs and may need a new transcode. Outputs in your storage don't expire.

Chunkify deletes every transcode record automatically. `delete_at` shows when, and a `transcoding.deleted` event is sent:

| Status | Record deleted |
| --- | --- |
| `expired` | 3 days after the output expires. |
| `ready` in your storage | When your team's data retention period ends. |
| `failed` | When your team's data retention period ends. |
| `cancelled` | When your team's data retention period ends. |

The data retention period is counted from when the transcode was created. A record is always kept for at least 3 days after it becomes ready, fails or is cancelled.

Automatic deletion removes only the Chunkify record; it never deletes outputs in your storage. Save any file locations or metadata your application needs before `delete_at`.

[Delete a transcode](/docs/api-reference/transcodings/delete-transcoding) removes a ready, failed, cancelled, or expired resource once processing and cleanup have stopped. By default, files in your storage are preserved.

Pass the `delete_files=true` query parameter to request output-file deletion as well. If storage deletion fails, records remain available for a retry, but files already deleted cannot be restored. Temporary output keeps its expiry after record deletion.
