---
title: Bring your own creative
description: Upload an image or a video that you own, and register it into the provider library of one advertiser, so that an ad there can use it. All from your AI client.
---

You have an image or a video, and you want an ad of one advertiser to use it. Ask your agent. With the five `asset_*` tools, the agent uploads the file to AdCrunch as an Asset. Then it registers the Asset into the provider library of that advertiser.

## Two words

This job uses two words of AdCrunch: an [Asset](/concepts#asset) and a [Registration](/concepts#registration). An Asset belongs to your organization. A Registration puts an Asset in the provider library of one [advertiser](/concepts#advertiser), and one Asset can have a Registration with each of your advertisers.

:::info[You register into an advertiser, not into a provider]

Your organization can have several advertisers on one provider. Each Registration names one advertiser. The agent finds the advertiser with [`list_advertisers`](/mcp/tools/list-advertisers).

:::

## The job, step by step

### 1. Ask for the upload

> "Upload spring-sale.mp4 from my Downloads folder to AdCrunch."

The agent calls [`asset_create_upload`](/mcp/tools/asset-create-upload) with the name of the file. AdCrunch reserves an Asset and gives the agent an upload URL. The URL is valid for one hour, and it can write this one file only.

### 2. The agent sends the file

The agent reads the file and sends it to the upload URL, with an HTTP `PUT` from its own runtime. The file goes straight to storage. It does not pass through the conversation.

:::warning[Your client must be able to send the file]

The `PUT` goes to `*.r2.cloudflarestorage.com`. The agent must be able to read the file and send an HTTP request, for example from a shell or a code tool. If your client restricts the network, it must allow that host. A client that can only call MCP tools cannot upload a file.

:::

### 3. The agent finalizes the upload

The agent calls [`asset_finalize`](/mcp/tools/asset-finalize). AdCrunch knows nothing about the file until it arrives, so it checks the stored file now. It reads the header of the file, and it checks the bytes against the type that the upload declared. A file that passes becomes a `ready` Asset of your organization. AdCrunch deletes a file that fails, and the agent tells you why. To try again, the agent starts a new upload.

When you name an advertiser in your request, the agent can start the Registration in the same call.

### 4. The agent registers the Asset

> "Put it in the Acme Meta account."

The agent calls [`asset_register`](/mcp/tools/asset-register) with the Asset and the advertiser. The call returns at once, with a `running` Registration. The provider takes the file in the background.

### 5. The agent checks until the Registration settles

> "Is the video ready in the Acme account yet?"

The agent calls [`asset_get`](/mcp/tools/asset-get), and reads the Registration with that advertiser. An image is ready as soon as the provider takes it. A video can stay `running` for several minutes while the provider processes it. That is normal, and it is not a failure. When the Registration is `ready`, you see the id that the provider gave the file, and an ad of that advertiser can use the file.

To see the Assets of your organization, ask:

> "What creative do we have, and where is each file registered?"

The agent calls [`asset_list`](/mcp/tools/asset-list). Each Asset comes with its Registrations.

## What AdCrunch accepts

| Kind  | Types                | Largest file |
| ----- | -------------------- | ------------ |
| Image | GIF, JPEG, PNG, WebP | 30 MiB       |
| Video | MP4, QuickTime (MOV) | 4 GiB        |

AdCrunch cannot see the file before it arrives, so it checks the stored bytes at finalize. AdCrunch deletes a file that fails the check. The agent then gets one of these codes:

- `too_large`: the file is over the limit for its kind.
- `unsupported_type`: the upload declared a type that is not in the table.
- `type_mismatch`: the bytes are a different type from the type that the upload declared.
- `unreadable`: the bytes are no accepted type, or the file ends before its header does.

A provider can have lower limits of its own. When the provider refuses a file, the Registration is `failed`, and the Asset stays with your organization.

## The state of a Registration

| State | What it means | What the agent does |
| --- | --- | --- |
| `running` | The provider takes or processes the file. | It checks again later with `asset_get`. |
| `ready` | The file is in the provider library of the advertiser, with the id of the provider. | It can build an ad from the Asset. |
| `failed` | The Registration failed. `failureReason` gives the reason. | It registers the Asset again with `asset_register`. It does not upload the file again. |

The tools show a `ready` Asset only. An upload that never finished does not show in the Assets of your organization.

## Guardrails

- **A Registration puts nothing live.** It makes a file available to an ad of one advertiser. It creates no ad and spends no money. On Meta, the agent builds an ad creative from a registered Asset with [`meta_create_creative`](/mcp/tools/meta-create-creative), which needs `mutation:write`.
- **Its own scopes.** The two reads need `asset:read`. The upload, the finalize and the Registration need `asset:write`. None of them needs `mutation:write`, because a file in a provider library changes no delivery. See [Auth & scopes](/mcp/auth).
- **No copy in the provider library.** While an Asset has a `running` or `ready` Registration with an advertiser, a second Registration with that advertiser fails with `already_registered`. When the agent registers again after a `failed` Registration, AdCrunch replaces the failed one. So a retry is safe.
- **Your organization only.** An Asset or an advertiser that is not in your organization gives `not_found`. An id that does not exist gives the same answer, so nobody can find out whether an id is real.
- **A failed Registration is not a failed upload.** When the Registration fails, the Asset stays with your organization. The agent registers it again, and does not upload the file again.
- **The upload URL is a key.** Anybody who has the URL can write that one file until the URL expires, one hour after the reservation.

Each failed call carries a code. [Errors](/mcp/errors) describes the shape of a failed call. [What to expect](/mcp/what-to-expect) states the rules that each tool follows, such as which organization your client acts for.

## Providers

AdCrunch registers files into the libraries of Meta and TikTok. Meta takes the bytes from AdCrunch. TikTok fetches the file itself, and applies its own limits to it. [What each provider supports](/connect/providers#register-creative) states what happens with an advertiser of another provider.

## The tools of this job

- [`asset_list`](/mcp/tools/asset-list): list the Assets of your organization, each with its Registrations.
- [`asset_get`](/mcp/tools/asset-get): read one Asset, and the state of each Registration.
- [`asset_create_upload`](/mcp/tools/asset-create-upload): reserve an Asset, and get the upload URL.
- [`asset_finalize`](/mcp/tools/asset-finalize): check the stored file, and make it a `ready` Asset.
- [`asset_register`](/mcp/tools/asset-register): register an Asset into the provider library of one advertiser.
