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

# Image understanding API: images and PDFs

> Analyze images and PDFs with GPT-6, GPT-5.6, and Gemini through LaoZhang API: URLs, Base64, multiple images, detail, and PDFs in Chat Completions and Responses.

Send images or PDFs to a multimodal model and get a text answer back. Use it for screenshot Q\&A, invoice extraction, UI review, or comparing two versions of an image. The same request works with GPT-6, GPT-5.6, and Gemini models; only `model` changes.

| Item | Details |
| - | - |
| Endpoint | `POST https://api.laozhang.ai/v1/chat/completions` |
| Request | A `text` part and an `image_url` part in the same user message |
| Image source | A public image URL or a Base64 data URL |
| Answer | `choices[0].message.content` |
| Example model | `gpt-6-sol` |

## Choose a model

All of these models are usage-billed in the `default` group. Prices are in the [model catalog](/en/models).

| Provider | Model IDs | Good for |
| - | - | - |
| OpenAI | `gpt-6-astra` | The hardest image and document reasoning; highest price |
| OpenAI | `gpt-6-sol`, `gpt-5.6-terra` | General image and document understanding |
| OpenAI | `gpt-6-luna` | Cost-sensitive work such as bulk screenshot Q\&A or classification |
| Google | `gemini-3.8-flash`, `gemini-3.7-flash`, `gemini-3.5-flash-lite` | Images, plus tasks that need audio or video input |
| Google | `gemini-4-argon` | Complex image tasks that need the strongest reasoning |
| Google | `gemini-3.1-pro-preview` | Complex images and documents that need stronger reasoning |

Qwen VL models such as `qwen3-vl-plus` also accept `image_url` requests, but the image URL must return a `Content-Length` header; otherwise the request fails with a 400, `Missing Content-Length of multimodal url`. The screenshot URL in these examples does not, so send it as Base64 when you use Qwen.

Each input type goes through a specific endpoint:

| Input | OpenAI models | Gemini models |
| - | - | - |
| Images | Chat Completions, Responses | Chat Completions, [native Gemini API](/en/api-reference/gemini#include-an-image) |
| PDF | Chat Completions, Responses; see [Read a PDF](#read-a-pdf) | [Native Gemini API](/en/api-reference/gemini#send-a-pdf-or-audio-file) only |
| Audio | Not accepted; to transcribe, use the [audio API](/en/api-capabilities/audio-transcription) | [Native Gemini API](/en/api-reference/gemini#send-a-pdf-or-audio-file) only |
| Video | Not accepted | [Video understanding API](/en/api-capabilities/video-understanding) |

## Before you start

Create an API key in [Token management](https://api.laozhang.ai/token) with its billing mode set to Usage first (recommended) or Usage-based, export it in your terminal, and install the OpenAI SDK for the Python examples:

```bash theme={null}
export LAOZHANG_API_KEY="YOUR_LAOZHANG_API_KEY"
python -m pip install openai
```

## Send an image URL

The example image is a screenshot of the LaoZhang API console's token page. The prompt asks the model which buttons are outlined in red.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl --fail-with-body --max-time 120 \
      "https://api.laozhang.ai/v1/chat/completions" \
      -H "Authorization: Bearer $LAOZHANG_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "gpt-6-sol",
        "messages": [{
          "role": "user",
          "content": [
            {"type": "text", "text": "Which buttons are outlined in red? Answer in one sentence."},
            {"type": "image_url", "image_url": {"url": "https://docs.laozhang.ai/images/key-manage.png"}}
          ]
        }]
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    from openai import OpenAI

    client = OpenAI(
        api_key=os.environ["LAOZHANG_API_KEY"],
        base_url="https://api.laozhang.ai/v1",
        timeout=120.0,
        max_retries=0,
    )
    response = client.chat.completions.create(
        model="gpt-6-sol",
        messages=[{
            "role": "user",
            "content": [
                {"type": "text", "text": "Which buttons are outlined in red? Answer in one sentence."},
                {
                    "type": "image_url",
                    "image_url": {"url": "https://docs.laozhang.ai/images/key-manage.png"},
                },
            ],
        }],
    )
    print(response.choices[0].message.content)
    ```
  </Tab>
</Tabs>

The answer should name the Add (新增) and Copy (复制) buttons. To try another model, such as `gemini-3.8-flash`, change only `model`.

The model service downloads the image itself, so your own URLs must open on the public internet without a login or cookies.

## Send a local image as Base64

For a file on your machine, encode it as a data URL, `data:<MIME type>;base64,<data>`, and send it in the same `image_url.url` field. This example reads `photo.jpg` from the current directory.

<Tabs>
  <Tab title="cURL">
    A Base64 image is too long for the command line, so write the request body to a file first and send that file:

    ```bash theme={null}
    python - <<'PY'
    import base64
    import json
    from pathlib import Path

    image = base64.b64encode(Path("photo.jpg").read_bytes()).decode("ascii")
    body = {
        "model": "gpt-6-sol",
        "messages": [{
            "role": "user",
            "content": [
                {"type": "text", "text": "List the main objects in this image."},
                {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image}"}},
            ],
        }],
    }
    Path("vision-request.json").write_text(json.dumps(body), encoding="utf-8")
    PY

    curl --fail-with-body --max-time 120 \
      "https://api.laozhang.ai/v1/chat/completions" \
      -H "Authorization: Bearer $LAOZHANG_API_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @vision-request.json
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import base64
    import mimetypes
    import os
    from pathlib import Path
    from openai import OpenAI

    path = Path("photo.jpg")
    mime_type = mimetypes.guess_type(path.name)[0] or "image/jpeg"
    data_url = f"data:{mime_type};base64,{base64.b64encode(path.read_bytes()).decode('ascii')}"

    client = OpenAI(
        api_key=os.environ["LAOZHANG_API_KEY"],
        base_url="https://api.laozhang.ai/v1",
        timeout=120.0,
        max_retries=0,
    )
    response = client.chat.completions.create(
        model="gpt-6-sol",
        messages=[{
            "role": "user",
            "content": [
                {"type": "text", "text": "List the main objects in this image."},
                {"type": "image_url", "image_url": {"url": data_url}},
            ],
        }],
    )
    print(response.choices[0].message.content)
    ```
  </Tab>
</Tabs>

The MIME type must match the file, for example `image/jpeg` for a JPEG or `image/png` for a PNG.

## Compare several images

Add one `image_url` part per image in the same message. The model reads them in order, so you can compare two versions or combine information across images. Refer to the images by position in your prompt ("the first image", "the second image") for more reliable answers.

```python theme={null}
import base64
import os
from pathlib import Path
from openai import OpenAI

def to_data_url(path: str) -> str:
    data = base64.b64encode(Path(path).read_bytes()).decode("ascii")
    return f"data:image/png;base64,{data}"

client = OpenAI(
    api_key=os.environ["LAOZHANG_API_KEY"],
    base_url="https://api.laozhang.ai/v1",
    timeout=120.0,
    max_retries=0,
)
response = client.chat.completions.create(
    model="gpt-6-sol",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "The first image is before the change and the second is after. List every difference."},
            {"type": "image_url", "image_url": {"url": to_data_url("before.png")}},
            {"type": "image_url", "image_url": {"url": to_data_url("after.png")}},
        ],
    }],
)
print(response.choices[0].message.content)
```

## Trade detail for tokens

OpenAI models accept a `detail` setting on each `image_url`:

| Value | Effect |
| - | - |
| `auto` | Default; the model decides |
| `low` | Processes a low-resolution version and uses far fewer input tokens; good for the gist of an image or for classification |
| `high` | Processes at high resolution; use it for small text, tables, and dense interfaces |

```json theme={null}
{"type": "image_url", "image_url": {"url": "https://docs.laozhang.ai/images/key-manage.png", "detail": "low"}}
```

Gemini models ignore `detail`; their token usage does not change.

## Read a PDF

OpenAI models read PDFs directly; you do not need to convert pages to images. Encode the PDF as a Base64 data URL and send it in a `file` part with a `filename`:

```python theme={null}
import base64
import os
from pathlib import Path
from openai import OpenAI

pdf_data = base64.b64encode(Path("invoice.pdf").read_bytes()).decode("ascii")

client = OpenAI(
    api_key=os.environ["LAOZHANG_API_KEY"],
    base_url="https://api.laozhang.ai/v1",
    timeout=120.0,
    max_retries=0,
)
response = client.chat.completions.create(
    model="gpt-6-sol",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "What are the invoice number, total due, and due date?"},
            {
                "type": "file",
                "file": {
                    "filename": "invoice.pdf",
                    "file_data": f"data:application/pdf;base64,{pdf_data}",
                },
            },
        ],
    }],
)
print(response.choices[0].message.content)
```

The model reads every page, so it can answer questions whose details span several pages.

<Warning>
  **Gemini models ignore `file` parts in Chat Completions.**

  * The request still returns 200, but the PDF is dropped and the model says nothing was attached or answers without it.
  * To analyze a PDF with Gemini, use the [native Gemini API](/en/api-reference/gemini#send-a-pdf-or-audio-file).
</Warning>

## Use the Responses API

OpenAI models also accept images and PDFs through the [Responses API](/en/api-manual#responses-api), as `input_image` and `input_file` parts:

```python theme={null}
import base64
import os
from pathlib import Path
from openai import OpenAI

pdf_data = base64.b64encode(Path("invoice.pdf").read_bytes()).decode("ascii")

client = OpenAI(
    api_key=os.environ["LAOZHANG_API_KEY"],
    base_url="https://api.laozhang.ai/v1",
    timeout=120.0,
    max_retries=0,
)
response = client.responses.create(
    model="gpt-6-sol",
    input=[{
        "role": "user",
        "content": [
            {"type": "input_text", "text": "Which buttons are outlined in red? Also give the invoice number."},
            {"type": "input_image", "image_url": "https://docs.laozhang.ai/images/key-manage.png"},
            {
                "type": "input_file",
                "filename": "invoice.pdf",
                "file_data": f"data:application/pdf;base64,{pdf_data}",
            },
        ],
    }],
)
print(response.output_text)
```

In `input_image`, `image_url` is a plain string: a public URL or a Base64 data URL. Gemini models do not support the Responses API; call them with Chat Completions or the native Gemini API.

## Read the answer

The answer is plain text in `choices[0].message.content`, and the response has the same shape as any Chat Completions reply. Add `"stream": true` to stream the answer; image requests stream the same way as text.

`usage.prompt_tokens` includes the tokens for images and files. Check [call logs](/en/faq/call-logs) for the actual charge.

Vision models can misread details, such as a digit in a similar-looking number. Review the output before you rely on it for amounts, IDs, or legal, medical, financial, or identity decisions.

## Use Gemini's native format

In Gemini's native `generateContent` format, Gemini models accept PDFs, audio, and video as well as images:

* Images: [Include an image](/en/api-reference/gemini#include-an-image)
* PDFs and audio: [Send a PDF or audio file](/en/api-reference/gemini#send-a-pdf-or-audio-file)
* MP4 video, frames and audio: [Video understanding API](/en/api-capabilities/video-understanding)

## FAQ

### Which model reads images most accurately?

For complex interfaces, small text, and multi-image comparisons, start with `gpt-6-sol` or `gpt-6-astra`. For simple, high-volume recognition, `gpt-6-luna` or `gemini-3.5-flash-lite` costs less. Before you go live, compare candidate models on your own images for accuracy and token usage.

### Can I send a PDF directly?

Yes. With OpenAI models, use a `file` part in Chat Completions or `input_file` in Responses; see [Read a PDF](#read-a-pdf). With Gemini models, use the [native Gemini API](/en/api-reference/gemini#send-a-pdf-or-audio-file), because Chat Completions drops the PDF.

### Can I send audio to the model?

GPT-6 and GPT-5.6 do not accept audio input; an `input_audio` part returns a 400. If you only need a transcript, use the [audio API](/en/api-capabilities/audio-transcription). If the model needs to listen and answer questions, use a Gemini model through the [native Gemini API](/en/api-reference/gemini#send-a-pdf-or-audio-file).

### Can I send video?

OpenAI models do not accept video. Gemini models analyze the frames and audio of an MP4 through the native API, or through a Base64 data URL in a `video_url` part in Chat Completions; see the [Video understanding API](/en/api-capabilities/video-understanding).

### The model says it received no image or file. What now?

Check `usage.prompt_tokens` first. A few dozen tokens means the attachment was not read. Common causes:

* The image URL needs a login or no longer works.
* The data URL's MIME type does not match the file, or the Base64 is incomplete.
* A Gemini model received a `file` or `input_audio` part, which Chat Completions drops for Gemini.

### How are images billed?

Images and PDFs are converted to input tokens and billed with your text at the model's price. For OpenAI models, `"detail": "low"` cuts image tokens substantially; Gemini models ignore `detail`. See [call logs](/en/faq/call-logs) for the tokens and cost of each request.

## Related documentation

* [OpenAI images and vision guide](https://developers.openai.com/api/docs/guides/images-vision)
* [OpenAI file inputs guide](https://developers.openai.com/api/docs/guides/pdf-files)
* [OpenAI protocol: Chat Completions](/en/api-reference/chat-completions)
* [Gemini protocol: generateContent](/en/api-reference/gemini)
* [Video understanding API](/en/api-capabilities/video-understanding)
* [Audio transcription and speech](/en/api-capabilities/audio-transcription)
* [Model catalog and pricing](/en/models)
* [Data and log boundaries](/en/faq/data-security)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.