---
title: document_finalize
description: Finish an upload. AdCrunch reads the type and the size from the stored file, not from what the agent declared.
---

This tool is the last step of an upload. AdCrunch checks the stored file and adds it to the brand.

> "Upload our brand book to Acme."

After the agent sends the bytes, it calls `document_finalize`. AdCrunch reads the type and the size from the stored file. You then see the file in the files of the brand, or the reason that AdCrunch refused it.

The job guide [Describe a brand](/mcp/tools/describe-a-brand) shows each step of the job.

## Reference

Complete a document upload once you have PUT the bytes to the URL from document_create_upload. Size and type are read from what actually landed, not from what you declared — so this can reject a file that the upload itself accepted.

### Input

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `document_id` | string | yes | The document id returned by document_create_upload. |

### Output

A successful call returns this object in `structuredContent`.

| Field | Type | Always present | Description |
| --- | --- | --- | --- |
| `document` | object | yes | A finalized document. |
| `document.createdAt` | number | yes | Milliseconds since the Unix epoch, in UTC. |
| `document.filename` | string | yes | The name of the file at upload. |
| `document.id` | string | yes | The id of the document (`doc_…`). |
| `document.mimeType` | string | yes | The media type of the stored file. AdCrunch reads it from the file at finalize. |
| `document.name` | string | yes | The display name. It is the filename until someone renames it. |
| `document.sizeBytes` | number | yes | The size of the stored file, in bytes. AdCrunch reads it from the file at finalize. |
| `document.targetId` | string | yes | The id of the brand that holds the document (`brd_…`). |
| `document.targetType` | string | yes | The kind of record that holds the document: `brand`. |
| `document.url` | string | yes | The public URL of the file. Each person who has the URL can read the file. |

### 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.

- `not_found`
- `no_object`
- `unsupported_type`
- `too_large`
- `forbidden`
- `invalid_request`
- `internal_error`

### Scope

The token must hold `brand: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.
- **Idempotent.** A second call with the same arguments changes nothing more.
- **Closed world.** The tool reads and writes the data of AdCrunch only.

### Example

The arguments:

```json
{
  "document_id": "doc_5e2b41"
}
```

The result, in `structuredContent`:

```json
{
  "document": {
    "createdAt": 1790000000000,
    "filename": "acme-brand-guidelines.pdf",
    "id": "doc_5e2b41",
    "mimeType": "application/pdf",
    "name": "acme-brand-guidelines.pdf",
    "sizeBytes": 1482064,
    "targetId": "brd_6a9c33",
    "targetType": "brand",
    "url": "https://documents.adcrunch.dev/org_3a7f10/doc_5e2b41"
  }
}
```
