Contents

Ollama REST API Tutorial: Call /api/chat and /api/generate with curl

Ollama provides an HTTP API in the background at http://localhost:11434 by default. The CLI, Open WebUI, and various libraries communicate with models through this API.

/api/chat: chat

curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [
    { "role": "system", "content": "Please answer in Traditional Chinese." },
    { "role": "user", "content": "Why is the sky blue? Explain in two sentences." }
  ],
  "stream": false
}'

The response has the following format. This is an actual response to sending hi to qwen3:0.6b (Ollama 0.40):

{
  "model": "qwen3:0.6b",
  "created_at": "2026-10-12T14:04:31.457272357Z",
  "message": {
    "role": "assistant",
    "content": "Hello! How can I assist you today? 😊 If you have any questions or need help, feel free to ask!",
    "thinking": "Okay, the user just said \"hi\" and I need to respond. ..."
  },
  "done": true,
  "done_reason": "stop",
  "total_duration": 10507470186,
  "load_duration": 26072287,
  "prompt_eval_count": 11,
  "prompt_eval_duration": 274566000,
  "eval_count": 112,
  "eval_duration": 10179865000
}
  • message.content: the model's answer.
  • message.thinking: the reasoning process of a reasoning model. Qwen3 thinks by default; add "think": false to the request if you don't need it.
  • done_reason: stop means the response ended normally; length means it was truncated after reaching the length limit.
  • All time fields are in nanoseconds (10507470186 ≈ 10.5 seconds). eval_count ÷ eval_duration gives the number of tokens generated per second.

Multi-turn conversations

The API itself doesn't remember previous messages. To continue a conversation, include the full message history:

{
  "model": "qwen3:8b",
  "messages": [
    { "role": "user", "content": "My name is Alex." },
    { "role": "assistant", "content": "Hello, Alex!" },
    { "role": "user", "content": "What is my name?" }
  ]
}

role can be system, user, assistant, or tool (a tool result; see Tool calling).

/api/generate: one-shot text generation

When you don't need a conversation structure, you can use /api/generate:

curl http://localhost:11434/api/generate -d '{
  "model": "qwen3:8b",
  "prompt": "Translate this sentence into English: The weather is beautiful today.",
  "stream": false
}'

The answer is in the response field. In general, /api/chat is the recommended choice.

Streaming responses

stream defaults to true: each time the model generates a short piece of text, it returns a JSON line. The done value in the final line is true.

curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [{ "role": "user", "content": "Count from 1 to 5" }]
}'
{"message":{"role":"assistant","content":"1"},"done":false}
{"message":{"role":"assistant","content":"、2"},"done":false}
...
{"message":{"role":"assistant","content":""},"done":true,"eval_count":12}

Streaming lets users see the response right away, so nearly all chat interfaces use it.

options: adjust parameters

{
  "model": "qwen3:8b",
  "messages": [{ "role": "user", "content": "Write a slogan" }],
  "options": {
    "temperature": 0.9,
    "num_ctx": 8192,
    "num_predict": 100,
    "seed": 42
  },
  "stream": false
}

The available parameters are the same as Modelfile's PARAMETER values; see the Modelfile tutorial.

keep_alive: control how long a model stays loaded

{ "model": "qwen3:8b", "keep_alive": "1h" }
  • Send only model, without a message, to preload a model.
  • "keep_alive": 0 unloads the model immediately after it responds.
  • "keep_alive": -1 keeps the model loaded indefinitely.

Image input

Vision models can accept base64-encoded images in a message:

IMG=$(base64 -w0 photo.jpg)   # macOS: base64 -i photo.jpg
curl http://localhost:11434/api/chat -d "{
  \"model\": \"gemma3\",
  \"messages\": [{
    \"role\": \"user\",
    \"content\": \"Describe this image\",
    \"images\": [\"$IMG\"]
  }],
  \"stream\": false
}"

Thinking mode

For models that support thinking, you can control it with think:

{
  "model": "qwen3:8b",
  "messages": [{ "role": "user", "content": "How many r's are in strawberry?" }],
  "think": true,
  "stream": false
}

The thinking content is in message.thinking, and the final answer is in message.content. think can also be false; some models support levels such as "low", "medium", and "high".

Other commonly used endpoints

Method and pathPurpose
GET /api/tagsList downloaded models (equivalent to ollama list)
GET /api/psList loaded models
POST /api/showModel information
POST /api/pullDownload a model
DELETE /api/deleteDelete a model
POST /api/embedGenerate text embeddings; see Text embeddings and RAG
GET /api/versionOllama version
curl http://localhost:11434/api/tags
curl http://localhost:11434/api/show -d '{"model": "qwen3:8b"}'

OpenAI-compatible API

Ollama also provides endpoints compatible with the OpenAI API under /v1:

EndpointDescription
/v1/chat/completionsChat
/v1/completionsText completion
/v1/embeddingsEmbeddings
/v1/modelsModel list
/v1/responsesResponses API
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3:8b",
    "messages": [{ "role": "user", "content": "Hello" }]
  }'

Many programs and tools originally written for OpenAI can use local models by changing the base URL to http://localhost:11434/v1 and setting the API key to any value. See the next section for a Python example.


Updated October 12, 2026