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

# Images

> Send images to multimodal models

Sail accepts image inputs on multimodal base models. Images can be supplied as base64 data URIs or as URLs.

## Supported models

Multimodal support is per-model, and detailed in the [models](/models) page. Requesting image input on a non-multimodal model returns `400` with `model '<id>' does not support image input`.

## Limits

* Maximum of 20 images per request.
* Maximum of 20 MB per image. This is the size of the image bytes, not the base64-encoded length. There is no pixel-dimension limit.
* Must be a JPEG, PNG, WebP, or GIF.
* URL images can use `http://` or `https://` (`https://` recommended) and must be reachable from the public internet. If Sail can't fetch a URL within 10 seconds, the request fails with `400`.

## Responses API

Pass an `input_image` block inside a message's `content` array. The `image_url` value can be a data URI or a public URL.

```python theme={null}
from openai import OpenAI

client = OpenAI(base_url="https://api.sailresearch.com/v1", api_key="YOUR_KEY")

response = client.responses.create(
    model="moonshotai/Kimi-K2.6",
    input=[
        {
            "role": "user",
            "content": [
                {"type": "input_text", "text": "What's in this image?"},
                {
                    "type": "input_image",
                    "image_url": "https://example.com/cat.jpg",
                },
            ],
        }
    ],
)
print(response.output_text)
```

Equivalent with a base64 data URI:

```python theme={null}
import base64, pathlib

b64 = base64.b64encode(pathlib.Path("cat.jpg").read_bytes()).decode()
data_uri = f"data:image/jpeg;base64,{b64}"

response = client.responses.create(
    model="moonshotai/Kimi-K2.6",
    input=[
        {
            "role": "user",
            "content": [
                {"type": "input_text", "text": "What's in this image?"},
                {"type": "input_image", "image_url": data_uri},
            ],
        }
    ],
)
```

`detail` (`"auto"`, `"low"`, `"high"`) is supported.

## Chat Completions API

Use OpenAI's standard `image_url` content part.

```python theme={null}
response = client.chat.completions.create(
    model="moonshotai/Kimi-K2.6",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "What's in this image?"},
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://example.com/cat.jpg",
                        "detail": "auto",
                    },
                },
            ],
        }
    ],
)
```

Data URIs are accepted in the same `url` field:

```python theme={null}
"image_url": {"url": f"data:image/jpeg;base64,{b64}"}
```

## Messages API (Anthropic)

Use the Anthropic `image` content block. Both `base64` and `url` source types are supported.

```python theme={null}
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.sailresearch.com",
    api_key="YOUR_KEY",
)

# URL source
response = client.messages.create(
    model="moonshotai/Kimi-K2.6",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {"type": "url", "url": "https://example.com/cat.jpg"},
                },
                {"type": "text", "text": "What's in this image?"},
            ],
        }
    ],
)

# Base64 source
response = client.messages.create(
    model="moonshotai/Kimi-K2.6",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/jpeg",
                        "data": b64,  # raw base64 string, no data: prefix
                    },
                },
                {"type": "text", "text": "What's in this image?"},
            ],
        }
    ],
)
```

## Error cases

| Condition                                          | Status | Message                                              |
| -------------------------------------------------- | ------ | ---------------------------------------------------- |
| `model` is not multimodal                          | 400    | `model '<id>' does not support image input`          |
| More than 20 images in one request                 | 400    | `too many images: maximum 20 images per request`     |
| Image larger than 20 MB decoded                    | 400    | `image too large: exceeds maximum of ... bytes`      |
| Unsupported MIME type                              | 400    | `unsupported image type ...`                         |
| URL scheme not http/https                          | 400    | `unsupported URL scheme ...`                         |
| URL not reachable from the public internet         | 400    | `blocked: ...`                                       |
| URL returns non-200 or times out (10 s)            | 400    | `failed to download image: ...`                      |
| Data URI declared MIME does not match actual bytes | 400    | `declared type ... does not match detected type ...` |

## Notes

* If you already have the image bytes, sending them as a base64 data URI is typically faster than a URL.
* Image bytes are not cached across requests.
* LoRAs and image inputs can be combined on a multimodal base model that also supports LoRA (see [LoRAs](/loras)).
