# Create a transcode

> Create an H.264 MP4 transcode.

Create a transcode from an existing Source. When it is ready, download the file or make it available to your users.

## Before you begin

You need a Source in the same Project, a Project access token, and an [official SDK](/docs/integration/sdk). Replace the token and Source ID in the examples. Keep the token on your server.

Set your storage as the Project's default output destination for lasting exports. The example uses `exports/video.mp4`, relative to that storage's `base_prefix`. Choose a distinct filename for each export.

For testing, you can use a Project whose default is Chunkify temporary storage. Chunkify generates the output path there, and deletes the output 24 hours after publication.

For webhook notifications, [configure and verify your webhook](/docs/integration/webhooks) before creating the transcode. Subscribe to `transcoding.ready`, `transcoding.failed`, and `transcoding.cancelled`.

## Create a transcode

The format below creates an H.264 MP4 at the Source's dimensions and frame rate. Omitted settings use the [format defaults](/docs/transcoding/formats/mp4).

<ignore>
SDK publication check: drafted from api/openapi.json and existing SDK conventions. Add Transcodings models, create/retrieve/list/cancel/delete mappings, pagination and data unwrapping to the owning SDK generator configuration. Verify generated method names and Go union/format/storage types in TypeScript, Python, PHP and Go before publication.
</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.create({
        source_id: 'src_2G6MJiNz71bHQGNzGwKx5cJwPFS',
        format: {
            id: "mp4_h264",
        },
        storage: {
            path: 'exports/video.mp4',
        },
    });

    console.log(transcoding.id, transcoding.status);
}

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.create(
    source_id="src_2G6MJiNz71bHQGNzGwKx5cJwPFS",
    format={
        "id": "mp4_h264",
    },
    storage={
        "path": "exports/video.mp4",
    },
)

print(transcoding.id, transcoding.status)
```
</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->create(
    sourceID: 'src_2G6MJiNz71bHQGNzGwKx5cJwPFS',
    format: [
        'id' => 'mp4_h264',
    ],
    storage: [
        'path' => 'exports/video.mp4',
    ],
);

var_dump($transcoding->id, $transcoding->status);
```
</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.New(
		context.Background(),
		chunkify.TranscodingNewParams{
			SourceID: "src_2G6MJiNz71bHQGNzGwKx5cJwPFS",
			Format: chunkify.TranscodingNewParamsFormatUnion{
				OfMP4H264: &chunkify.TranscodingMP4H264Param{},
			},
			Storage: chunkify.TranscodingNewParamsStorage{
				Path: chunkify.String("exports/video.mp4"),
			},
		},
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(transcoding.ID, transcoding.Status)
}
```
</codeblock>
</codegroup>


Creation accepts the request and returns its current status; the file is not available until publication. Save the returned `id` for status checks and webhook correlation.

## Follow the process

Use [Get a transcode](/docs/api-reference/transcodings/get-transcoding) with that ID, or handle a verified webhook. Check periodically until `status` is `ready`, `failed`, or `cancelled`.

The `format` response contains the settings accepted for this request, including resolved dimensions, frame rate, and trim. Actual output properties appear in `files` after publication.

A `transcoding.ready` webhook contains the same resource structure at `data.transcoding`. Read every member of its `files` collection. See [Events](/docs/integration/events#transcoding-events) for the lifecycle event types.

## Retrieve the file

When the transcode is `ready`, use a file's `url` to download it, or its `cdn_url` when your output storage has CDN delivery configured. Do not infer the output key from the input Source path.

The signed `url` lasts at most ten minutes. Retrieve the transcode again for a fresh URL while the file remains available. For lasting delivery, use your storage and its configured CDN.

Check `error` if the transcode fails. [Lifecycle and files](/docs/transcoding/lifecycle) covers error handling, cancellation, and cleanup.

## Change the output

Choose [MP4](/docs/transcoding/formats/mp4), [WebM](/docs/transcoding/formats/webm), or [audio](/docs/transcoding/formats/audio).

Enable [per-title optimization](/docs/transcoding/per-title) when you want content-based video bitrate selection.
