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

# Media upload

> POST /v1/media/upload — upload images and videos for model input.

Upload reference images or videos before submitting a run. Returns a **public URL** to pass in model `input` fields (e.g. `image_url`, `image_urls`).

Requires scope **`runs:write`** and the same API key as inference.

## Request

`multipart/form-data` with field **`file`**:

| Field  | Type   | Required  | Description                           |
| ------ | ------ | --------- | ------------------------------------- |
| `file` | binary | **Yes**\* | `image/*` or `video/*`, max **50 MB** |

### curl

```bash theme={null}
curl -X POST "https://api.apisale.ai/v1/media/upload" \
  -H "Authorization: Key $APISALE_API_KEY" \
  -F "file=@./reference.png"
```

## Response (`201`)

<ResponseField name="url" type="string" required>
  HTTPS URL to use in run `input` (e.g. `"image_url": "https://..."`).
</ResponseField>

<ResponseField name="object_key" type="string" required>
  Internal storage key (for debugging).
</ResponseField>

<ResponseField name="content_type" type="string" required>
  MIME type, e.g. `image/png`.
</ResponseField>

<ResponseField name="size_bytes" type="number" required>
  Uploaded file size in bytes.
</ResponseField>

### Example

```json theme={null}
{
  "url": "https://cdn.apisale.ai/media/org_abc/uploads/2026/06/abc.png",
  "object_key": "org_abc/uploads/2026/06/abc.png",
  "content_type": "image/png",
  "size_bytes": 245760
}
```

## Errors

| HTTP | `error.code`                          | Cause                                                 |
| ---- | ------------------------------------- | ----------------------------------------------------- |
| 401  | `missing_api_key` / `invalid_api_key` | No or bad API key                                     |
| 400  | `invalid_media`                       | Missing file, bad MIME, or file too large (max 50 MB) |

See [Error codes](/get-started/errors-and-limits) for the full catalog.

## Related

* [Submit a run](/model-apis/submit-run)
* [Authentication](/get-started/authentication)


## OpenAPI

````yaml openapi.json POST /v1/media/upload
openapi: 3.0.0
info:
  title: apisale Public API
  version: 0.1.0
  description: >-
    Generative media inference, account monitoring, and SDK-compatible routes
    for apisale.ai. Authenticate with `Authorization: Key YOUR_API_KEY`.
servers:
  - url: https://api.apisale.ai
security: []
paths:
  /v1/media/upload:
    post:
      tags:
        - Public Media
      summary: Upload image or video for use in run input
      description: >-
        Multipart upload. Returns a public URL to pass in model `input` fields
        (e.g. `image_url`). Max 50 MB. Requires `runs:write` scope.
      operationId: MediaController_upload
      parameters: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: image/* or video/*
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MediaUploadResponseDto'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    MediaUploadResponseDto:
      type: object
      properties: {}
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: 'API key: `Key sk-xxx` or `Bearer sk-xxx`'

````