Skip to content

Chat Completions · image

Sends an image along with the question and receives the answer as text. Same endpoint as text calls, with `content` as a list of parts.

Updated on Aug 10, 2026

The same address as text calls, with one difference in the body: the message content stops being a string and becomes a list of parts, one of them carrying the image. Route, authentication and response envelope are identical.

The guided use — what an image costs, which model to choose, how to turn a document into fields in your database — is in Image understanding. This page is the contract: what goes in the body and what comes back.

POSThttps://api.hinow.ai/v1/chat/completionsBearer

Sends one or more images along with the question and returns the answer as text.

Parâmetros

  • modelstring· bodyobrigatório

    Namespaced model id. `hinow/hivision` is the one dedicated to image reading; the language models accept images too.

  • messagesarray· bodyobrigatório

    Conversation messages, as in any call. The call is stateless: the context is whatever you send.

  • messages[].contentstring | array· bodyobrigatório

    A string, when the message is text only. A **list of parts**, when there is an image.

  • content[].typestring· bodyobrigatório

    `"text"` or `"image_url"`, depending on the part.

  • content[].textstring· body

    The request, in the `text` part.

  • content[].image_url.urlstring· body

    Public address of the image, or a `data:` URL with the file in base64.

  • streamboolean· body

    Returns tokens as they come out, over SSE. `usage` arrives in the last event.

  • temperaturenumber· body

    Controls sampling variation. For field extraction, use low values.

  • max_tokensinteger· body

    Ceiling on response tokens. When it cuts, `finish_reason` comes back as `"length"`.

  • response_formatobject· body

    `{"type": "json_object"}` requests content in JSON. Validate the fields in the application.

Respostas

200Reading completed
{
  "id": "chatcmpl-R2dSu3p8...",
  "object": "chat.completion",
  "model": "hinow/hivision",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "O gráfico mostra..." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 389, "completion_tokens": 42, "total_tokens": 431 }
}
400Body out of format, or a model that does not serve Chat Completions (`invalid_request_error`)
404Model does not exist or is not enabled (`model_not_found`)
429Per-minute limit exceeded (`rate_limit_exceeded`)
502The API could not fetch the image from the given address

The message content

It is the only structural change compared with a text call. Where a string used to go, a list goes — and the order of the parts is the order in which the model reads them. Put the request before the image when it defines what to look at.

"messages": [{
  "role": "user",
  "content": [
    {"type": "text", "text": "O que este gráfico mostra? Responda em português, em uma frase."},
    {"type": "image_url", "image_url": {"url": "https://exemplo.com/grafico.png"}}
  ]
}]
PartField that mattersWhat for
texttextThe request, in natural language
image_urlimage_url.urlThe image, by address or embedded

The role is still user

The list of parts applies to the user message. General instructions — response language, output format — still work better in a system message, as a string, as in any text call.

The image: address or base64

The url field accepts both, and both work:

  • Public address — the API fetches the image, so it must be reachable over the internet. An address on localhost or behind a login will not do.
  • The embedded image — a data: URL with the file in base64. It does not depend on publishing the image anywhere, and it is the path for the file the user has just uploaded.
curl https://api.hinow.ai/v1/chat/completions \
  -H "Authorization: Bearer $HINOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "hinow/hivision",
    "messages": [{
      "role": "user",
      "content": [
        {"type": "text", "text": "O que este gráfico mostra? Responda em português, em uma frase."},
        {"type": "image_url", "image_url": {"url": "https://exemplo.com/grafico.png"}}
      ]
    }]
  }'

A URL the API cannot reach returns 502

The error does not say the address is invalid — it says the call failed. If one specific public host fails while others work, the problem is the reachability of that address, not a lack of URL support. When in doubt, send the image embedded as base64.

Accepted formats

FormatResult
PNGWorks
JPEGWorks
WebPWorks

The declared type is not what decides

A PNG sent as data:image/jpeg;base64,... was read normally — it is the file content that counts. Even so, declare the right type: it is what keeps your own code honest when the format changes.

The response

The same envelope as a text call: choices[0].message.content with the answer, finish_reason with the reason it stopped and usage with the consumption. There is no separate field for the image — it already went into prompt_tokens.

The count has a behaviour worth knowing beforehand: the same picture sent at 512px (19 KB) and at 1024px (55 KB) consumed 389 prompt tokens both times. Shrinking the image does not make the call cheaper, and it may cost the legibility of small text — send it at a resolution where a person would be able to read it.

More than one image

Add another image_url part to the same list. It works for comparing two versions of a document, checking before and after, or asking for a conclusion about a set.

"content": [
  {"type": "text", "text": "Estes dois documentos são da mesma empresa? Responda sim ou não e por quê."},
  {"type": "image_url", "image_url": {"url": "https://exemplo.com/nota-a.png"}},
  {"type": "image_url", "image_url": {"url": "https://exemplo.com/nota-b.png"}}
]

Each image adds to the bill: with two at 1024px, the prompt went to 660 tokens — against 389 for a single one.

Streaming

With stream: true the response arrives over server-sent events, exactly as in a text call: the chunks come in choices[0].delta.content, usage only appears in the last event and the stream ends with data: [DONE].

The image changes nothing here — it is consumed whole on input, before the first token comes out. What changes is the wait until that first token, which is longer than in a text-only call.

Errors

SituationCodeWhat to do
The API cannot reach the image address502Send the image embedded as base64
content as a string, with an image expected400Switch to a list of parts
A model that does not serve Chat Completions, such as hinow/hiembed400Check the modality at GET https://api.hinow.ai/v1/models
Model does not exist or is not enabled404Check the namespaced id
Per-minute limit exceeded429Retry with progressive backoff
A call with no image at all200It answers normally, but usage comes back zeroed

Confirm your account's contract

Availability, prices and modalities evolve. GET https://api.hinow.ai/v1/models returns the current catalog — but treat the category field as informative: models listed only as text_to_text accepted images in testing.

Carry on

Was this page helpful?