> ## Documentation Index
> Fetch the complete documentation index at: https://support.myapps.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Files & uploads

> Get images and other media into a workflow run

Workflows that take an image, video, or audio input need that file reachable by URL. You either point at a URL you already host, or upload the file to Pixio storage first.

## Option 1 — a URL you already have

If the file is already publicly reachable, pass the URL straight through in `inputs`:

```json theme={null}
{
  "deployment_id": "your-deployment-id",
  "inputs": {
    "input_image": "https://example.com/reference.png"
  }
}
```

Simplest path — but the URL must be publicly reachable for the whole run. Signed URLs that expire mid-run, or links behind auth, will fail.

## Option 2 — upload to Pixio storage

For local files, get an upload URL first. `GET /upload-url` takes:

| Parameter   | Required | Description                                        |
| ----------- | -------- | -------------------------------------------------- |
| `type`      | Yes      | MIME type — `image/png`, `image/jpg`, `image/jpeg` |
| `file_size` | Yes      | Size of the file in bytes                          |

Response:

```json theme={null}
{
  "upload_url": "...",
  "file_id": "...",
  "download_url": "..."
}
```

Three-step flow:

<Steps>
  <Step title="Request an upload URL">
    Send the MIME type and exact byte size.
  </Step>

  <Step title="PUT the file to upload_url">
    Upload the bytes directly to the returned URL.
  </Step>

  <Step title="Use download_url as the input">
    Pass `download_url` as your workflow's image input.
  </Step>
</Steps>

```js theme={null}
const fs = require('fs');

const buffer = fs.readFileSync('reference.png');

const { upload_url, download_url } = await client.getUploadUrl({
  type: 'image/png',
  file_size: buffer.length,
});

await fetch(upload_url, {
  method: 'PUT',
  headers: { 'Content-Type': 'image/png' },
  body: buffer,
});

await client.runWorkflow({
  deployment_id: 'your-deployment-id',
  inputs: { input_image: download_url },
});
```

<Warning>
  `file_size` must be the **actual** byte length. A mismatch between the size you declare and the bytes you send causes the upload to be rejected. Use `buffer.length` or `fs.statSync(path).size` — never an estimate.
</Warning>

## Getting it right

* **Match the MIME type to the file.** A `.jpg` sent as `image/png` may fail or confuse the graph.
* **Reuse uploads.** One `download_url` can feed many runs — don't re-upload the same reference per run.
* **Upload before you run.** The file must exist before the graph reaches the node that reads it.
* **Keep the `file_id`.** It's your handle on the stored file.

## Outputs

Outputs are produced during the run's `uploading` phase — which is exactly why `uploading` isn't terminal. Read output URLs only after the status is `success`; earlier, they may be missing or incomplete.

<Tip>
  Treat output URLs as something to fetch and store on your side if you need them long-term. Don't assume a URL from a run last month still resolves.
</Tip>

## Errors

| Response                       | Meaning                                             |
| ------------------------------ | --------------------------------------------------- |
| `401 Invalid or expired token` | Check the Bearer header                             |
| `500` with an `error` field    | Upload URL generation failed — the message says why |
