Skip to content

How to Use the Ollama API: Python, curl and OpenAI-Compatible Guide (2026)

12–18 minutes
Smiling woman with long dark hair in a black and white hoodie holds a white card showing the Ollama llama logo in a cosy lamp-lit living room, with the hook text 'Ollama API in 5 minutes' and the fj. badge

Ollama is great in the terminal, but the real fun starts when your own scripts and apps can talk to your local models. That is what the Ollama API is for.

Every time Ollama is running, it quietly serves a REST API on your computer at http://localhost:11434. You can call it with curl, with the official Python library, or with any OpenAI client by changing one line.

This guide shows you how to use the Ollama API step by step: your first request, chat with history, streaming, JSON output, tool calling, thinking models, embeddings, the OpenAI-compatible endpoints, remote access and the errors you will hit along the way.

TL;DR

  • Base URL: http://localhost:11434/api for the native API, http://localhost:11434/v1 for OpenAI-compatible calls. No API key is needed locally.
  • Main endpoints: /api/chat (conversations), /api/generate (single prompt), /api/embed (embeddings), /api/tags (list models), /api/ps (loaded models).
  • Python: pip install ollama, then ollama.chat(model="gemma4", messages=[...]).
  • Streaming is on by default. Send "stream": false to get one JSON reply.
  • OpenAI apps: set base_url="http://localhost:11434/v1/" and any non-empty api_key.

What the Ollama API Is

When you install Ollama, it runs a small server in the background. The desktop app, the ollama command and tools like Open WebUI all talk to that same server.

The API is simply that server’s front door. Anything you can do in the terminal, such as running a model, listing models or pulling a new one, you can also do with an HTTP request.

Three things make it easy to work with:

  • No key locally. Ollama’s docs state that the local API at http://localhost:11434 does not require authentication.
  • Plain JSON. You send JSON and get JSON (or a stream of JSON lines) back.
  • Stable. The API is not strictly versioned, but Ollama says it is expected to stay backwards compatible, and deprecations are announced in the release notes.

If you have not installed Ollama yet, or you run it in a container, start with our Ollama in Docker guide. The API works the same either way.

Ollama API Endpoints at a Glance

Endpoint Method What it does
/api/chat POST Chat with a list of messages (system, user, assistant, tool). Best for most apps.
/api/generate POST One prompt in, one completion out. Also loads or unloads a model.
/api/embed POST Turns text (or a list of texts) into embedding vectors.
/api/tags GET Lists the models you have downloaded.
/api/ps GET Lists the models loaded in memory right now.
/api/show POST Model details: parameters, template, capabilities, thinking levels.
/api/pull, /api/delete, /api/copy, /api/create POST / DELETE Manage models, same as the matching ollama commands.
/api/version GET Returns the Ollama version.
/v1/chat/completions, /v1/responses, /v1/embeddings, /v1/models POST / GET OpenAI-compatible versions for existing OpenAI code.
Which one should I use? Use /api/chat for anything conversational, /api/generate for one-shot jobs like summaries, and /v1 only when you are plugging Ollama into code or apps written for OpenAI.

Step 1: Check the API Is Running

  1. Start Ollama. On Windows and macOS, open the Ollama app (you will see the llama icon in the tray or menu bar). On Linux, the install script runs it as a service; you can also run ollama serve in a terminal.
  2. Pull a model if you have none: ollama pull gemma4. Any model works; swap the name in every example below.
  3. Open http://localhost:11434 in your browser. You should see the text “Ollama is running”.
  4. List your models through the API: curl http://localhost:11434/api/tags. You get a JSON list with each model’s name, size and digest.

If the browser cannot connect, Ollama is not running or something else is using port 11434. See Troubleshooting.

Step 2: Your First Request with curl

Here is the simplest possible chat call. It turns streaming off so you get one clean JSON object back.

curl http://localhost:11434/api/chat -d '{
  "model": "gemma4",
  "messages": [{"role": "user", "content": "Why is the sky blue? One sentence."}],
  "stream": false
}'

The answer is in message.content. The reply also carries timing data that is handy for speed tests:

Field Meaning
total_duration Whole request time
load_duration Time spent loading the model into memory
prompt_eval_count Input tokens
prompt_eval_cached_count Input tokens read from the cache
eval_count / eval_duration Output tokens and the time taken to generate them

All durations are in nanoseconds. To get tokens per second, divide eval_count by eval_duration and multiply by 1,000,000,000.

On Windows PowerShell, the single quotes above do not work the same way. Use curl.exe and put the JSON in a file, then run curl.exe http://localhost:11434/api/chat -d "@body.json". Or skip curl and use Python.

For a one-off prompt without a message list, /api/generate takes a prompt and returns the text in response:

curl http://localhost:11434/api/generate -d '{
  "model": "gemma4",
  "prompt": "Write a haiku about GPUs.",
  "stream": false
}'

Step 3: Use the Ollama API from Python

The official ollama package wraps the REST API so you do not have to build requests by hand. It needs Python 3.8 or newer.

  1. Install it: pip install -U ollama (or uv add ollama).
  2. Make sure Ollama is running and the model is pulled.
  3. Save and run this script:
from ollama import chat

response = chat(
    model="gemma4",
    messages=[{"role": "user", "content": "Give me 3 tips for writing clean Python."}],
)
print(response.message.content)

To keep a conversation going, append each reply to the list and send the whole list again. The model has no memory between calls; the history you send is its memory.

from ollama import chat

messages = [{"role": "system", "content": "You are a friendly, concise tutor."}]

while True:
    user = input("You: ")
    if user.lower() in ("quit", "exit"):
        break
    messages.append({"role": "user", "content": user})
    reply = chat(model="gemma4", messages=messages)
    messages.append({"role": "assistant", "content": reply.message.content})
    print("AI:", reply.message.content)

Ollama on another machine or port? Create a client with a host:

from ollama import Client
client = Client(host="http://192.168.1.50:11434")
print(client.chat(model="gemma4", messages=[{"role": "user", "content": "Hi"}]).message.content)

There is also an AsyncClient with the same methods for asyncio apps, and an official JavaScript library (npm i ollama) that mirrors the Python one.

Prefer plain HTTP? The requests library works fine too:

import requests
r = requests.post("http://localhost:11434/api/chat", json={
    "model": "gemma4",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": False,
})
r.raise_for_status()
print(r.json()["message"]["content"])

Streaming Responses

Chat and generate stream by default. You get newline-delimited JSON (application/x-ndjson): one small object per chunk, and a final object with "done": true plus the timing stats.

In Python, set stream=True and loop:

from ollama import chat

for chunk in chat(
    model="gemma4",
    messages=[{"role": "user", "content": "Explain VRAM like I am 10."}],
    stream=True,
):
    print(chunk.message.content, end="", flush=True)

With raw requests, read line by line:

import json, requests
with requests.post("http://localhost:11434/api/chat", json={
    "model": "gemma4",
    "messages": [{"role": "user", "content": "Count to 5"}],
}, stream=True) as r:
    for line in r.iter_lines():
        if not line:
            continue
        part = json.loads(line)
        if "error" in part:
            raise RuntimeError(part["error"])
        print(part["message"]["content"], end="", flush=True)
Watch for mid-stream errors. If something fails after streaming starts, the HTTP status stays 200 and the error arrives as a final {"error": "..."} line. Always check for an error key, as in the loop above.

JSON and Structured Outputs

Need data, not prose? Use the format field. Set it to "json" for any valid JSON, or pass a JSON schema to force an exact shape.

The cleanest way in Python is a Pydantic model:

from ollama import chat
from pydantic import BaseModel

class Country(BaseModel):
    name: str
    capital: str
    languages: list[str]

resp = chat(
    model="gemma4",
    messages=[{"role": "user", "content": "Tell me about Canada. Reply as JSON."}],
    format=Country.model_json_schema(),
    options={"temperature": 0},
)
country = Country.model_validate_json(resp.message.content)
print(country.capital)

Ollama’s docs suggest also describing the schema in your prompt to ground the model, and a temperature of 0 makes the output more predictable. Note that structured outputs work on local models; Ollama’s cloud does not support them at the moment.

Tool Calling

Tool calling lets the model ask your code to run a function, such as fetching the weather or querying a database, and then use the result in its answer. You need a model that supports tools; filter by “tools” on the Ollama model library.

The Python library can turn a normal function with a docstring into a tool definition for you:

from ollama import chat

def get_temperature(city: str) -> str:
    """Get the current temperature for a city

    Args:
      city: The name of the city
    """
    return {"New York": "22°C", "London": "15°C"}.get(city, "unknown")

messages = [{"role": "user", "content": "What is the temperature in London?"}]
resp = chat(model="qwen3", messages=messages, tools=[get_temperature])
messages.append(resp.message)

for call in resp.message.tool_calls or []:
    result = get_temperature(**call.function.arguments)
    messages.append({"role": "tool", "tool_name": call.function.name, "content": result})

final = chat(model="qwen3", messages=messages)
print(final.message.content)

The flow is always the same: send tools, read tool_calls, run the function yourself, send the result back with role tool, and ask again. Ollama never runs your code; it only tells you what the model wants to call.

Thinking Models

Reasoning models can show their working in a separate field. Set think on a chat or generate request:

  • true turns thinking output on, false asks for none (if the model allows it).
  • Some models take a level instead, such as "low", "medium", "high" or "max".
  • Call /api/show for the model to see which values it supports and its default.
resp = chat(model="qwen3", messages=[{"role": "user", "content": "How many r's in strawberry?"}], think=True)
print("Thinking:", resp.message.thinking)
print("Answer:", resp.message.content)

Chat returns message.thinking and message.content; generate returns thinking and response. Hide the thinking in your UI if you only want the answer.

Embeddings

Embeddings turn text into numbers so you can search by meaning, which is the base of RAG (chat with your documents). Pull an embedding model first, for example ollama pull embeddinggemma or all-minilm.

import ollama
out = ollama.embed(model="all-minilm", input=["Ollama runs models locally.", "The sky is blue."])
print(len(out.embeddings), len(out.embeddings[0]))

The /api/embed endpoint accepts one string or a list, truncates long inputs by default ("truncate": true), and takes an optional dimensions value on models that support it. Use the same embedding model for indexing and for searching, or the vectors will not match.

OpenAI-Compatible API

Lots of apps and libraries only speak the OpenAI format. Ollama serves compatible endpoints under /v1, so you can point them at your PC instead.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1/", api_key="ollama")  # key is required but ignored
resp = client.chat.completions.create(
    model="gemma4",
    messages=[{"role": "user", "content": "Say hello in French"}],
)
print(resp.choices[0].message.content)
OpenAI endpoint Supported in Ollama Notes
/v1/chat/completions Yes Streaming, tools, vision, JSON mode
/v1/completions Yes Legacy text completions
/v1/responses Yes (stateless) No previous_response_id or conversations
/v1/embeddings, /v1/models Yes Model list matches ollama list
/v1/audio/speech, /v1/audio/transcriptions Yes, with speech/audio models WAV output by default, not MP3

Two gotchas worth knowing. First, the OpenAI format has no way to set the context window, so if you need a bigger one, create a model with PARAMETER num_ctx in a Modelfile (shown below) and call that name.

Second, if a tool insists on a model called gpt-4o or similar, run ollama cp gemma4 gpt-4o to give your model that alias.

Ollama also accepts Anthropic-style clients: set the base URL to http://localhost:11434 and the client adds /v1/messages itself.

Options, Context Size and keep_alive

The native API takes model settings in an options object:

{
  "model": "gemma4",
  "messages": [{"role": "user", "content": "Summarise this report..."}],
  "options": {"temperature": 0.3, "num_ctx": 16384, "seed": 42},
  "keep_alive": "30m",
  "stream": false
}
Setting What it does Tip
temperature Randomness 0 to 0.3 for facts and JSON, 0.7+ for creative text
num_ctx Context window in tokens Bigger uses more VRAM; Ollama’s default depends on your VRAM
seed Fixed seed Same seed + same prompt gives repeatable output
num_predict Max output tokens Stops runaway answers
keep_alive How long the model stays loaded Default 5m; -1 keeps it loaded, 0 unloads now

To make a setting permanent for /v1 calls, create a Modelfile:

FROM gemma4
PARAMETER num_ctx 16384

Then run ollama create gemma4-16k -f Modelfile and use gemma4-16k as the model name. You can also set a default for every model with the OLLAMA_CONTEXT_LENGTH environment variable.

Not sure how big a context your card can take? Our guide to running Kimi K3.1 Pro locally shows how memory and context size add up.

Call Ollama from Another Computer

By default Ollama only listens on 127.0.0.1, so other devices cannot reach it. To serve your home network:

  1. Windows: quit Ollama, open “Edit environment variables for your account”, add OLLAMA_HOST = 0.0.0.0:11434, then start Ollama again.
  2. macOS app: run launchctl setenv OLLAMA_HOST "0.0.0.0:11434" and restart the app.
  3. Linux service: run sudo systemctl edit ollama, add Environment="OLLAMA_HOST=0.0.0.0:11434" under [Service], then sudo systemctl daemon-reload && sudo systemctl restart ollama.
  4. Allow port 11434 through your firewall for your local network only.
  5. Test from the other device: curl http://<your-pc-ip>:11434/api/tags.
Security: the local API has no password. Never forward port 11434 to the internet. For remote access, use a VPN such as Tailscale or put a reverse proxy with authentication in front of it.

Calling Ollama from a web page or browser extension? Browsers block cross-origin requests unless you allow them. Add your origin to OLLAMA_ORIGINS, for example OLLAMA_ORIGINS=chrome-extension://*.

Want a no-code way to build on the API instead? Our n8n + Ollama local AI agent guide connects the same endpoint to workflows.

Ollama Cloud API (Optional)

Ollama also hosts larger models in its cloud. You can use them two ways:

  • Through your local server: run ollama signin once, then call a cloud model name (such as one ending in -cloud) on localhost:11434 exactly like a local one.
  • Directly: create a key at ollama.com/settings/keys, set OLLAMA_API_KEY, and call https://ollama.com/api or https://ollama.com/v1 with the header Authorization: Bearer $OLLAMA_API_KEY.

Keys do not expire, so keep them out of browser code and git, and revoke any key you leak.

Troubleshooting

Problem Likely cause Fix
Connection refused on port 11434 Ollama is not running Open the app or run ollama serve; check http://localhost:11434
404 “model not found” Model not pulled or name typo Run ollama list and use the exact name, including the tag
First reply takes 10 to 60 seconds Model loading from disk Normal once; keep it loaded with "keep_alive": "30m" or -1
Python json.decoder.JSONDecodeError Reading a streamed reply as one JSON Send "stream": false or read line by line
Model forgets earlier messages History not sent, or context too small Send the full messages list; raise num_ctx
Other devices cannot connect Bound to 127.0.0.1 or firewall Set OLLAMA_HOST=0.0.0.0:11434, restart, open the port on LAN
CORS error in the browser Origin not allowed Add the origin to OLLAMA_ORIGINS
Docker app cannot reach Ollama on the host localhost means the container Use http://host.docker.internal:11434
OpenAI client error about the key Empty api_key Pass any string, such as "ollama"
Tool calls never appear Model lacks tool support Pick a model tagged “tools” on ollama.com
429 or 502 errors Cloud rate limit or cloud model unreachable Back off and retry; local models do not have this limit

Slow answers usually mean the model does not fit in VRAM and spills to system RAM. Run ollama ps and check the PROCESSOR column; anything less than 100% GPU will be slower. A smaller model or quant fixes it.

If your models live on a full drive, our guide to moving Ollama models to another drive helps.

My Take

For most people the best starting point is the official Python library with /api/chat. It is a few lines of code, handles streaming and tools neatly, and keeps you close to Ollama’s own features like think, keep_alive and num_ctx.

Reach for the /v1 endpoints when you want to reuse OpenAI code or drop Ollama into an app that already expects OpenAI. And if you outgrow your GPU, the same code can call Ollama’s cloud models just by changing the model name.

FAQ

Does the Ollama API need an API key?

Not for local use. The API at localhost:11434 has no authentication. You only need a key to call Ollama’s hosted cloud directly at ollama.com.

What port does the Ollama API use?

Port 11434. Change it with OLLAMA_HOST, for example OLLAMA_HOST=127.0.0.1:8080.

What is the difference between /api/chat and /api/generate?

/api/chat takes a list of messages with roles and suits conversations and tools. /api/generate takes one prompt and suits one-shot tasks. Both stream by default.

Is the Ollama API compatible with OpenAI?

Yes, for the common parts. Use http://localhost:11434/v1 as the base URL. Chat completions, completions, stateless Responses, embeddings, models and audio endpoints are supported.

How do I stop Ollama from unloading my model?

Send "keep_alive": -1 with your request or set the OLLAMA_KEEP_ALIVE environment variable. Send "keep_alive": 0 to unload a model immediately.

Can I send images to the Ollama API?

Yes, with a vision model. Add base64 images in an images list on the message (native API), or use the OpenAI image format on /v1/chat/completions. The Python library also accepts file paths.

Can several apps use the API at the same time?

Yes. Requests queue up, and OLLAMA_NUM_PARALLEL controls how many each model handles at once (default 1). More parallel requests use more memory.

Sources

Free weekly email

Get new AI guides every week

One short weekly email with our newest local AI, ComfyUI and AI tool guides. No spam, no pop-ups, just the good stuff.

Free. Unsubscribe anytime in one click. We only use your email to send this newsletter. See our privacy policy.

Smiling woman with long dark hair in a black and white hoodie holds a white card showing the Ollama llama logo in a cosy lamp-lit living room, with the hook text 'Ollama API in 5 minutes' and the fj. badge