---
title: asset_create_upload
description: Reserve an Asset and get a short-lived URL to upload the file to. Step one of bringing your own creative in.
---

Ask to upload a file to AdCrunch. This tool is the first step of the upload: AdCrunch reserves an Asset and gives the agent a URL to send the file to.

> "Upload logo.png from my desktop to AdCrunch."

The agent calls this tool with the name of the file. Then it sends the file to the URL from its own runtime, so the file does not pass through the conversation. Then it finalizes the upload with [`asset_finalize`](/mcp/tools/asset-finalize). You see the file in the Assets of your organization after the finalize. The URL is valid for one hour. Your client must let the agent send the file: the job guide states what it needs.

This tool is part of the job [Bring your own creative](/mcp/tools/bring-your-own-creative).

## Reference

Reserve an Asset and get a short-lived URL to upload the file to.

**You upload the bytes yourself**: send an HTTP `PUT` to the returned `uploadUrl` with the file as the body and its `Content-Type` set. The bytes must never pass through this conversation — read the file and PUT it from your own runtime.

This requires your runtime to reach `*.r2.cloudflarestorage.com`; if network access is restricted, that host must be allowed. Once the PUT succeeds, call asset_finalize.

### Input

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `filename` | string | yes | The original filename, including its extension. |

### Output

A successful call returns this object in `structuredContent`.

| Field | Type | Always present | Description |
| --- | --- | --- | --- |
| `assetId` | string | yes | The Asset this reservation made. Finalize it with this id. |
| `expiresAt` | number | yes | When the upload URL stops being accepted, in milliseconds since the Unix epoch, UTC. |
| `uploadUrl` | string | yes | PUT the bytes here, directly. The URL is the credential: anybody holding it can write that one object until it expires. |

### Failure codes

A failed call has `isError` set, and `structuredContent.error` holds one of these codes. [Errors](/mcp/errors) describes the shape of a failed call.

- `reservation_failed`
- `forbidden`
- `invalid_request`
- `internal_error`

### Scope

The token must hold `asset:write`. [Auth & scopes](/mcp/auth) lists each scope.

### Annotations

A client reads these hints. A hint that the tool does not declare has the default value of the MCP specification.

- **Writes.** The tool can change data.
- **Destructive.** The tool can make a change that you cannot undo. A client can ask you to confirm before it calls the tool.
- **Not idempotent.** A second call with the same arguments can change more.
- **Closed world.** The tool reads and writes the data of AdCrunch only.

### Example

The arguments:

```json
{
  "filename": "spring-sale.mp4"
}
```

The result, in `structuredContent`:

```json
{
  "assetId": "ast_7c1e9a",
  "expiresAt": 1790003600000,
  "uploadUrl": "https://b7f3c81a29d64e0fa5c3d1e8b0947265.r2.cloudflarestorage.com/assets/org_3a7f10/ast_7c1e9a?X-Amz-Expires=3600&X-Amz-Date=20260921T141320Z&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=4f8e2a6c1b9d7e3f5a0c2b4d6e8f1a3c%2F20260921%2Fauto%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Signature=7d1c4a9f2e8b0536c1a7e94d2b6f038a5c1e9b7d3f6a2c805d4e1b93a7f0c625"
}
```
