# Files & uploads

Many generations take file inputs: reference images, inpainting masks, poses, depth maps, or audio. You upload a file once, then pass its `file_id` into generation requests.

## Upload flow

Uploads go **directly to storage** with a resumable upload. You request a signed URL, then upload the bytes yourself.

1. **Request an upload URL**  
```bash  
curl -X POST https://api.app.layer.ai/api/v2/workspaces/$WORKSPACE_ID/files/upload-url \
  -H "Authorization: Bearer $LAYER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "content_type": "image/png" }'  
# → { "file_id": "…", "upload_url": "https://storage.googleapis.com/…", "content_type": "image/png", "source_type": "asset" }  
```
2. **Start a resumable session** by POSTing to `upload_url` with the `x-goog-resumable: start` header; the response’s `Location` is your session URI.
3. **Upload the bytes** with a `PUT` to the session URI.

Caution

The `upload_url` **expires in 15 minutes**. Request it right before uploading.

## Supported types & sizes

| Type    | Content types                     | Max size |
| ------- | --------------------------------- | -------- |
| Image   | image/png, image/jpeg, image/webp | 64 MB    |
| Video   | video/mp4                         | 100 MB   |
| Audio   | audio/wav, audio/mpeg             | 64 MB    |
| Archive | application/zip                   | 100 MB   |

## Using files in a generation

Pass the returned `file_id` into a generation request. Reference images and other guidance go in `guidance_files`; an inpainting mask goes in `mask` (request it with `source_type: "mask"`, and it must be an image):

```jsonc
{
  "model_id": "MODEL_ID",
  "parameters": {
    "prompt": "replace the sky with aurora",
    "guidance_files": [{ "file_id": "FILE_ID" }],
    "mask": { "file_id": "MASK_FILE_ID" }
  }
}
```

Layer resolves each `file_id` to the stored object internally: you don’t pass URLs.

## Annotating images

Instead of describing where an edit goes, you can mark it on the image. Add `annotations` to an `init_image` or `reference_image` guidance file: a list of numbered marks, each with a `note` saying what to do there. On the image to edit a mark says what to change; on a reference it says what to use from it (“this hat”), or with `REMOVE`, what to leave out. Points run from `(0, 0)` at the top left to `(1, 1)` at the bottom right of the image: the file as uploaded or, for a video or a 3D model, the frame taken from it (`video_to_image` / `mesh_to_image`), after any crop or rotation: marks are the last edit on the image, placed on it as it is framed.

```jsonc
{
  "guidance_files": [
    {
      "file_id": "FILE_ID",
      "type": "init_image",
      "annotations": {
        "items": [
          { "id": "lantern", "kind": "BOX", "points": [{ "x": 0.16, "y": 0.08 }, { "x": 0.32, "y": 0.36 }], "note": "make the lantern glow green" },
          { "id": "bottle", "kind": "ELLIPSE", "intent": "REMOVE", "points": [{ "x": 0.66, "y": 0.13 }, { "x": 0.79, "y": 0.34 }] },
          { "id": "apples", "kind": "BOX", "points": [{ "x": 0.3, "y": 0.36 }, { "x": 0.55, "y": 0.64 }] },
          { "id": "move", "kind": "ARROW", "intent": "MOVE", "source_id": "apples", "points": [{ "x": 0.42, "y": 0.5 }, { "x": 0.12, "y": 0.8 }] },
          { "id": "barrel", "kind": "PIN", "points": [{ "x": 0.1, "y": 0.82 }], "note": "add a small wooden barrel" }
        ]
      }
    }
  ]
}
```

| Kind         | Points                             |
| ------------ | ---------------------------------- |
| BOX, ELLIPSE | Two opposite corners of the region |
| ARROW        | Tail, then head                    |
| FREEHAND     | The path, 2 to 512 points          |
| PIN          | One point                          |

A mark’s `intent` is `EDIT` (the default), `REMOVE`, or `MOVE`: an arrow that moves what the box or ellipse named by `source_id` encloses to where it points. A run takes up to 32 marks. Leave `color` unset: a colour that stands out against the image is chosen and stored with the run, so you can show the marks as they were sent.

How a model reads the marks is in its capabilities, under `visual_annotations`:

* **`RENDERED`**: the model is sent your images unchanged, plus a copy of each marked image with the numbered marks drawn on it, and the prompt gets a numbered list of your notes for each. Each copy takes one of the model’s reference image slots.
* **`NATIVE_BOXES`**: the model takes boxes as input, on the `init_image` only. Only `BOX` marks and arrows that move a box can be sent; any other mark, or marks on a reference, is refused.
* **Absent**: the model does not read marks. They are left out, and the run reports the adjustment.

Tip

Keep the prompt for what applies to the whole image and the notes for what applies to one mark. A mark without a note applies the prompt to that area.

## Downloads

There is **no download endpoint**. Generated outputs are returned as URLs in the run result (see [Async jobs](/docs/async-jobs)); fetch those directly.
