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.
- Base URL:
http://localhost:11434/apifor the native API,http://localhost:11434/v1for 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, thenollama.chat(model="gemma4", messages=[...]). - Streaming is on by default. Send
"stream": falseto get one JSON reply. - OpenAI apps: set
base_url="http://localhost:11434/v1/"and any non-emptyapi_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:11434does 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. |
/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
- 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 servein a terminal. - Pull a model if you have none:
ollama pull gemma4. Any model works; swap the name in every example below. - Open
http://localhost:11434in your browser. You should see the text “Ollama is running”. - 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.
- Install it:
pip install -U ollama(oruv add ollama). - Make sure Ollama is running and the model is pulled.
- 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)
{"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:
trueturns thinking output on,falseasks for none (if the model allows it).- Some models take a level instead, such as
"low","medium","high"or"max". - Call
/api/showfor 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:
- Windows: quit Ollama, open “Edit environment variables for your account”, add
OLLAMA_HOST=0.0.0.0:11434, then start Ollama again. - macOS app: run
launchctl setenv OLLAMA_HOST "0.0.0.0:11434"and restart the app. - Linux service: run
sudo systemctl edit ollama, addEnvironment="OLLAMA_HOST=0.0.0.0:11434"under[Service], thensudo systemctl daemon-reload && sudo systemctl restart ollama. - Allow port 11434 through your firewall for your local network only.
- Test from the other device:
curl http://<your-pc-ip>:11434/api/tags.
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 signinonce, then call a cloud model name (such as one ending in-cloud) onlocalhost:11434exactly like a local one. - Directly: create a key at ollama.com/settings/keys, set
OLLAMA_API_KEY, and callhttps://ollama.com/apiorhttps://ollama.com/v1with the headerAuthorization: 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
- Ollama docs: API introduction and base URLs
- Ollama API reference (endpoints and parameters)
- Ollama docs: OpenAI compatibility
- Ollama docs: structured outputs, tool calling and thinking
- Ollama docs: streaming, errors and usage metrics
- Ollama docs: FAQ (OLLAMA_HOST, OLLAMA_ORIGINS, keep_alive, context length)
- ollama-python library



