← Blog

Claude API Vision: Image Input Example That Works

2026-09-27 · 4 min read · SubToAPI Team

Claude's API accepts image input alongside text in the same message, so you can ask questions about a screenshot, a diagram, a scanned document, or a product photo and get a text response back. The short answer: you send a content array with an image block (base64-encoded data or a URL) and a text block in the same user message, then call the Messages endpoint as usual.

Below is a minimal working example, followed by the details that trip people up: image formats, size limits, multiple images, and how to combine vision with tool use or streaming.

The Basic Shape of a Vision Request

A vision-enabled message looks like this:

{
  "model": "claude-sonnet-4-5",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "image",
          "source": {
            "type": "base64",
            "media_type": "image/jpeg",
            "data": "<base64-encoded-image-data>"
          }
        },
        {
          "type": "text",
          "text": "What's in this image? Describe any text you can read."
        }
      ]
    }
  ]
}

Key points:

Full curl Example

Here's a working curl example against the SubToAPI gateway, which forwards to Claude with your sub_live_... key handling auth:

IMAGE_BASE64=$(base64 -i screenshot.png)

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "image",
            "source": {
              "type": "base64",
              "media_type": "image/png",
              "data": "'"$IMAGE_BASE64"'"
            }
          },
          {
            "type": "text",
            "text": "Extract all the text from this screenshot as plain text."
          }
        ]
      }
    ]
  }'

On macOS/Linux, base64 -i file works; on some Linux distros you need base64 -w 0 file to avoid line breaks in the output, which will break the JSON payload.

JavaScript Example

import fs from "fs";

const imageBuffer = fs.readFileSync("./invoice.jpg");
const imageBase64 = imageBuffer.toString("base64");

const response = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content: [
          {
            type: "image",
            source: {
              type: "base64",
              media_type: "image/jpeg",
              data: imageBase64
            }
          },
          {
            type: "text",
            text: "This is an invoice. Extract the vendor name, total amount, and due date as JSON."
          }
        ]
      }
    ]
  })
});

const data = await response.json();
console.log(data.content[0].text);

This pattern — image plus a structured extraction prompt — is one of the most common practical uses of vision: turning invoices, receipts, forms, and screenshots into structured data without a separate OCR pipeline.

Sending Multiple Images

You can include more than one image block in the same content array. This is useful for comparisons ("what changed between these two screenshots?") or multi-page documents:

{
  "content": [
    { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": "..." } },
    { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": "..." } },
    { "type": "text", "text": "Compare these two UI mockups and list the differences." }
  ]
}

There's a practical limit on how many images you can send per request and on total payload size — large batches of high-resolution images will hit token and payload limits fast, since each image consumes a meaningful chunk of the context window (roughly proportional to pixel count). For scanned documents, downscaling to a reasonable resolution before encoding (under ~1568px on the long edge) keeps requests fast and cheap without losing OCR-relevant detail.

Using Image URLs Instead of Base64

If your images are already hosted somewhere accessible, you can skip the base64 step entirely:

{
  "type": "image",
  "source": {
    "type": "url",
    "url": "https://example.com/chart.png"
  }
}

This is convenient for pipelines that already store images in S3 or a CDN — no need to download and re-encode.

Combining Vision with Streaming and Tools

Vision requests work the same way as any other Messages call, so they compose with the rest of the API. You can stream a response describing an image in real time (see /docs/streaming), and you can let Claude call tools based on what it sees in an image — for example, extracting a part number from a photo and then calling a lookup function (see /docs/tools). Nothing about the image block changes how streaming or tool calling behaves; it's just additional input content in the same message.

If you're routing Claude calls through SubToAPI to get a single HTTPS endpoint, usage metadata, and per-key limits across a team, vision requests are billed and tracked the same as text-only requests — check current plan details at /pricing, and see /docs/messages for the full request schema including image blocks.

questions

Does Claude API support image input in every model tier? Vision is supported on Claude's current model family (Sonnet, Opus, Haiku variants that include vision) — check the model card for the specific version you're calling, since older or text-only model IDs will reject image content blocks.

What image formats and sizes does the API accept? JPEG, PNG, GIF, and WebP, sent as base64 or via URL. There's no hard single-file size cap documented beyond general payload limits, but larger images cost more tokens, so resizing to a few hundred KB or under ~1568px on the long edge is the practical sweet spot.

Can I send a PDF instead of an image? Not as an image block. PDFs need to be converted to page images first (or extracted as text) before sending — the vision input type is strictly for image formats, not document containers.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →