Firstpass v0.2.1
DocsGuaranteeBenchmarksCLIGitHub

Docs / How Agents Talk to Models / Images & multimodal

Part A2 · Beyond the core pathModule 10 of 13

Images & multimodal

A message's content can be an array mixing text blocks and image blocks. Images — base64 or URL — are billed as input tokens, scaled by resolution: a typical screenshot adds ~1,500–3,200 tokens, as much as a page of text. The cost model (rate per Mtok) doesn't change; only the input-token count does.
An image content block is split by the provider into tiles based on its resolution, and every tile is billed as input tokens — so a larger or higher-resolution image costs more input tokens. A typical screenshot lands around 1,500 tokens, roughly a page of text. The per-token rate is unchanged; only the token count grows. An image is tiled by resolution — every tile is billed as input tokens screenshot · 1080×800 the image you send tiled split into fixed-size tiles more pixels → more tiles ≈ 1,500 tokens billed as INPUT as much as a page of text
An image isn't a flat fee — the provider tiles it by resolution and bills each tile as input tokens, so a bigger screenshot costs more. The rate per token is unchanged; the token count jumps, which is why a vision-heavy agent's bill climbs.

Every content value so far has been a plain string. The API also accepts an array of typed blocks, which is how you mix text and images in one turn. In our running example, the agent might be handed a screenshot of the failing CI run rather than raw terminal text — the PNG goes directly into the request alongside the user's question:

json
{
  "model": "claude-haiku-4-5",
  "max_tokens": 1024,
  "messages": [{
    "role": "user",
    "content": [
      {
        "type": "image",
        "source": {
          "type": "base64",        // or "url" → { "url": "https://…" }
          "media_type": "image/png",
          "data": "iVBORw0KGgo…"  // base64-encoded PNG
        }
      },
      {
        "type": "text",
        "text": "The CI run ended with this screenshot. What's wrong in orders.py?"
      }
    ]
  }]
}
Under the hood Images are billed as input tokens using a tile model: the image is resized to fit within a bounding box (2048 px on the long edge, 768 px on the short), then divided into 512×512 px tiles. Each tile costs a fixed token budget, plus a small base cost. A 1080×800 screenshot typically lands around 1,500 tokens — the same as a 300-line Python file. High-resolution images (4K screenshots, multi-page PDFs rendered as images) can exceed 3,000 tokens each.
Common mistake Sending images doesn't change the rate you're charged per token — it changes how many input tokens you consume. An agent that routinely attaches screenshots pays the same per-Mtok price but reads a much larger input on every call. Proxies like Firstpass treat has_images as a routing signal for exactly this reason: a vision-capable cheap model that can handle the image skips the expensive escalation.
Images land in content as typed blocks with a source (base64 or URL); they're billed as input tokens proportional to resolution — the rate stays flat, the count jumps, and has_images is a real routing signal.