# Begin upload

`begin_upload`

| Through | Form |
|---|---|
| HTTP | `POST https://api.markdownbrain.ai/v1/uploads` |
| MCP | tool `begin_upload` |
| CLI | `mdbrain call begin_upload` |

Start a staged upload, for content too large to send inside a call. Returns `upload_id`, a signed `url` and its `token`, and `expires_at` (two hours). PUT the bytes to `url` (with the Content-Type you declared), or send them over the resumable endpoint in `resumable` with the `x-signature` header it names; then commit: an image with [`upload_image`](/docs/operations/upload_image) and `upload_id` instead of `data_base64`. Committing an object larger than the declared `size` is refused.

**Who may call it:** agents and people.

**Writes:** yes.

## Arguments

| Name | Type | Required | Travels in | Description |
|---|---|---|---|---|
| `workspace_id` | string | yes | JSON body | The workspace the staged bytes belong to |
| `purpose` | "image" or "arguments" | yes | JSON body | `image` to commit with upload_image; `arguments` to name with an X-Arguments-Upload header on the HTTP API |
| `size` | integer | yes | JSON body | The exact size in bytes of what will be sent |
| `content_type` | string | yes | JSON body | The MIME type of what will be sent, e.g. image/png or application/json |

## Success

`201` with `application/json`.

## Example request

```sh
curl -X POST https://api.markdownbrain.ai/v1/uploads \
  -H "Authorization: Bearer $MDBRAIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"workspace_id":"00000000-0000-4000-8000-000000000010","purpose":"image","size":248310,"content_type":"image/png"}'
```

```sh
mdbrain call begin_upload \
  --workspace-id 00000000-0000-4000-8000-000000000010 \
  --purpose image \
  --size 248310 \
  --content-type image/png
```

## Example response

> Written from the code rather than captured from a call.

```json
{
  "upload_id": "00000000-0000-4000-8000-000000000500",
  "url": "https://example.supabase.co/storage/v1/object/upload/sign/images/00000000-0000-4000-8000-000000000021/00000000-0000-4000-8000-000000000010/staging/00000000-0000-4000-8000-000000000500?token=eyJhbGciOiJIUzI1NiJ9.placeholder",
  "token": "eyJhbGciOiJIUzI1NiJ9.placeholder",
  "expires_at": "2026-03-15T19:20:05.000000+00:00",
  "resumable": {
    "endpoint": "https://example.supabase.co/storage/v1/upload/resumable/sign",
    "headers": {
      "x-signature": "eyJhbGciOiJIUzI1NiJ9.placeholder"
    },
    "bucket": "images",
    "object_name": "00000000-0000-4000-8000-000000000021/00000000-0000-4000-8000-000000000010/staging/00000000-0000-4000-8000-000000000500"
  }
}
```

## Refusals

A refusal is a status code with `{ error: { code, message } }`. See [Errors](/docs/errors).
