API Reference
Specification and usage examples for the HTTP API that LLM AI Server with llama.cpp exposes on the device. It covers the Ollama-compatible endpoints (/api/*), the OpenAI-compatible endpoints (/v1/*), and the llama.cpp WebUI-compatible endpoints (/props, /slots, and more), based on the current OllamaApiServer implementation.
Related docs: User Manual | Technical Specification | Privacy Policy
Contents
1. Basics
- Base URL:
http://localhost:<port>(default port11434). While on Wi-Fi, a LAN URL (http://<device-ip>:<port>) is also available on the same port. - Shared port: The API and the WebUI are served on the same port. GET requests outside API paths fall through to the WebUI.
- Authentication: There is no API-key auth (the
Authorizationheader is ignored). Intended for same-device or local-network use. - CORS: All responses include
Access-Control-Allow-Origin: *, andOPTIONSpreflight returns204. - Content types: Request bodies are JSON (
application/json). Non-streaming responses are JSON; streaming responses use NDJSON (application/x-ndjson) for/api/*and SSE (text/event-stream) for/v1/*. - Model selection:
modelis a configuration (profile) name. List profiles via/api/tagsor/v1/models.
2. Compatibility summary
For the range that typical chat / generation clients use, the API is compatible with both the Ollama and OpenAI specifications. Because the app is built around a single on-device model and a single generation slot, some management endpoints and statistics fields are not provided.
| Category | Details |
|---|---|
| Ollama-compatible (implemented) | POST /api/generate, POST /api/chat, GET/POST /api/tags. Response shape is {model, created_at, response|message, done}. Tool paths add done_reason, tool_calls, and reasoning_content. |
| OpenAI-compatible (implemented) | POST /v1/chat/completions (SSE streaming terminated by data: [DONE]), GET /v1/models. Returns object, choices[].message/delta, and finish_reason. |
| llama.cpp WebUI-compatible | GET /props, GET /slots, GET /health (/v1/health), GET /models, and bundled WebUI serving. |
| Extensions (app-specific) | Multimodal inputs (image_url / input_audio), shared MCP / Function Definitions settings, reasoning_content, and an option to append performance metrics to the output text. |
| Not implemented (caveats) | OpenAI responses do not include id / created / usage. Ollama responses do not include statistics such as total_duration / eval_count / prompt_eval_count / context. Embeddings (/api/embed, /v1/embeddings), model management (/api/show, /api/pull, /api/ps, /api/version), and /v1/completions (legacy completions) are not provided. |
If you need token-usage style statistics, enable "Show Performance Metrics" in Output Settings. Token counts, processing time, and speed are appended after generation (in the final delta for OpenAI, as an extra chunk for Ollama).
3. Common behavior
3-1. Concurrency and busy queue
- There is a single inference slot (single generation). Additional requests during generation are queued (up to
10) and wait up to60seconds. - Queue overflow or wait timeout returns
503. - While a model reset is in progress, new requests are rejected and queued requests are aborted (
503).
3-2. Error responses
/api/* endpoints return plain JSON / text errors, while /v1/* endpoints return an OpenAI-style error object.
// /v1/* error shape
{
"error": {
"message": "No messages provided",
"type": "invalid_request_error",
"code": 400
}
}
| Status | Meaning |
|---|---|
400 | Invalid JSON, missing required fields, unsupported content[].type, unsupported modality, etc. |
404 | Unknown route |
405 | Unsupported HTTP method |
500 | Configuration load failure, generation failure, etc. |
503 | Busy (queue full / wait timeout / reset in progress) |
4. POST/api/generate
Single-prompt generation (Ollama generate compatible). Streaming (NDJSON) by default.
Request
| Field | Type | Description |
|---|---|---|
model | string | Profile name. Defaults to "default". |
prompt | string | User prompt. |
system | string? | Optional system prompt (overrides the configured one). |
stream | bool | Default true. Use false for a single response. |
tools | array? | Optional. Switches to the internal tool-execution loop (section 12). |
Non-streaming response
curl http://localhost:11434/api/generate -d '{
"model": "my-profile",
"prompt": "What is the capital of Japan?",
"stream": false
}'
{
"model": "my-profile",
"created_at": "2026-06-14T03:10:00Z",
"response": "The capital of Japan is Tokyo.",
"done": true
}
Streaming response (NDJSON)
One JSON object per line. Each chunk has "done": false with a partial response; a final chunk with "done": true closes the stream.
{"model":"my-profile","created_at":"...","response":"The","done":false}
{"model":"my-profile","created_at":"...","response":" capital is","done":false}
{"model":"my-profile","created_at":"...","response":"","done":true}
5. POST/api/chat
Conversation generation from a messages array (Ollama chat compatible). Streaming (NDJSON) by default.
Request
| Field | Type | Description |
|---|---|---|
model | string | Profile name. Defaults to "default". |
messages | array | Required. Array of {role, content}. role is system / user / assistant / tool. content is a string, or an array for multimodal input (section 11). |
stream | bool | Default true. |
tools | array? | Optional (section 12). |
Non-streaming response
curl http://localhost:11434/api/chat -d '{
"model": "my-profile",
"stream": false,
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "How tall is Mount Fuji?"}
]
}'
{
"model": "my-profile",
"created_at": "2026-06-14T03:10:00Z",
"message": { "role": "assistant", "content": "3,776 m." },
"done": true
}
Streaming response (NDJSON)
{"model":"my-profile","created_at":"...","message":{"role":"assistant","content":"3,776"},"done":false}
{"model":"my-profile","created_at":"...","message":{"role":"assistant","content":" m."},"done":false}
{"model":"my-profile","created_at":"...","message":{"role":"assistant","content":""},"done":true}
6. GETPOST/api/tags
List of available models (profiles). Ollama tags compatible.
curl http://localhost:11434/api/tags
{
"models": [
{
"name": "my-profile",
"model": "my-profile",
"modified_at": "2026-06-14T03:10:00Z",
"size": 0,
"details": {
"format": "gguf",
"family": "llama",
"parameter_size": "unknown",
"quantization_level": "unknown"
}
}
]
}
Fields such as size and parameter_size cannot be determined on-device, so they use fixed values (0 / "unknown"). Use /v1/models for richer status and modality information.
7. POST/v1/chat/completions
OpenAI Chat Completions compatible. Streaming (SSE) by default. Point the official OpenAI SDK's base_url at this server to use it.
Request
| Field | Type | Description |
|---|---|---|
model | string | Profile name. If empty/omitted, resolves to the currently loaded model, otherwise the default profile. |
messages | array | Required. OpenAI format. content is a string or an array of {type, ...} parts (section 11). |
stream | bool | Default true. |
tools / tool_choice / parallel_tool_calls | array / any / bool | Optional (section 12). |
| Sampling fields | number, etc. | temperature, top_p, top_k, min_p, presence_penalty, frequency_penalty, and more (section 10). Overrides settings per request. |
Non-streaming response
curl http://localhost:11434/v1/chat/completions -d '{
"model": "my-profile",
"stream": false,
"messages": [
{"role": "user", "content": "Say hello in Japanese."}
]
}'
{
"object": "chat.completion",
"model": "my-profile",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Konnichiwa!" },
"finish_reason": "stop"
}
]
}
Note: responses do not include id / created / usage. Clients that require these will see them as missing.
Streaming response (SSE)
First a chunk with delta.role="assistant", then chunks carrying delta.content, and finally a chunk with finish_reason:"stop" followed by data: [DONE].
data: {"object":"chat.completion.chunk","model":"my-profile","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","model":"my-profile","choices":[{"index":0,"delta":{"content":"Konni"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","model":"my-profile","choices":[{"index":0,"delta":{"content":"chiwa!"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","model":"my-profile","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
8. GET/v1/models & /models
Returns the OpenAI-compatible model list plus a llama.cpp WebUI-oriented models array (status and modalities).
curl http://localhost:11434/v1/models
{
"object": "list",
"data": [
{
"id": "my-profile",
"name": "my-profile",
"object": "model",
"owned_by": "llamacpp",
"created": 1781000000,
"in_cache": true,
"path": "/data/.../my-model.gguf",
"status": { "value": "loaded" },
"tags": []
}
],
"models": [
{
"name": "my-profile",
"model": "my-profile",
"modified_at": "2026-06-14T03:10:00Z",
"size": 4100000000,
"capabilities": ["multimodal"],
"modalities": { "vision": true, "audio": false },
"details": { "format": "gguf", "family": "llama", "parameter_size": "unknown", "quantization_level": "unknown" }
}
]
}
data[] is OpenAI-compatible; models[] is llama.cpp WebUI-compatible. modalities reflects actual support for loaded models, or values inferred from the file when not loaded.
9. GET/props, /slots, /health
Endpoints mainly used to initialize the bundled (llama.cpp-style) WebUI. Use ?model=<profile-name> to target a profile.
/props: Returnsdefault_generation_settings(n_ctxand sampling values),chat_template,modalities,model_path,build_info, andwebui_settings(system message, Think display, shared MCP / Function Definitions).total_slotsis1./slots: A slot array (one element) withn_ctx,params(sampling values), andis_processing./health,/v1/health:{"status":"ok","role":...,"webui":true}.
curl "http://localhost:11434/props?model=my-profile"
10. Sampling parameters
For /v1/chat/completions, including the following keys in the request body overrides the configured values for that request (unspecified fields fall back to the profile values).
| Key | Type | Maps to |
|---|---|---|
temperature | number | Temperature |
top_k | int | Top-k |
top_p | number | Top-p |
min_p | number | Min-p |
typ_p | number | Typical-p |
dynatemp_range / dynatemp_exponent | number | Dynamic temperature |
xtc_probability / xtc_threshold | number | XTC sampler |
repeat_last_n | int | Penalty window size |
repeat_penalty | number | Repeat penalty |
presence_penalty / frequency_penalty | number | Presence / Frequency penalty |
dry_multiplier / dry_base / dry_allowed_length / dry_penalty_last_n | number / int | DRY sampler |
mirostat / mirostat_tau / mirostat_eta | int / number | Mirostat |
Setting n_predict: 0 performs pre-encode only and returns an empty response early (useful for prompt-evaluation warm-up).
11. Multimodal inputs
/api/chat and /v1/chat/completions accept images and audio by passing content as a parts array. The loaded model must support vision / audio; otherwise the request returns 400.
| type | Description |
|---|---|
text / input_text | Text (text field). |
image_url | image_url.url is an HTTP/HTTPS image URL or a data:image/...;base64, data URL. Remote fetch is limited to 10 MB. |
input_audio | input_audio.data (base64) and input_audio.format ("wav" or "mp3"). |
curl http://localhost:11434/v1/chat/completions -d '{
"model": "my-vision-profile",
"stream": false,
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image."},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ..."}}
]
}
]
}'
// Audio input (wav / mp3)
{
"role": "user",
"content": [
{"type": "text", "text": "Transcribe this audio."},
{"type": "input_audio", "input_audio": {"data": "UklGR...", "format": "wav"}}
]
}
12. Tools / Function Calling
Passing tools in the request, or enabling shared MCP / Function Definitions in the app's MCP Settings, switches to the internal tool-execution loop. This works on /api/generate, /api/chat, and /v1/chat/completions.
toolsis an OpenAI-compatible array. Passing a non-array returns400.tool_choiceandparallel_tool_callsare accepted.- When shared MCP / Function Definitions are enabled, the same tool settings apply to the main prompt input and to each API.
- Responses may include
tool_callsreturned directly by the model, plus calls extracted from in-text tool-call markers orreasoning_content.
// OpenAI-compatible tool example (part of a non-streaming response)
{
"object": "chat.completion",
"model": "my-profile",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_1",
"type": "function",
"function": { "name": "get_weather", "arguments": "{\"city\":\"Tokyo\"}" }
}
]
},
"finish_reason": "tool_calls"
}
]
}
13. Client examples
OpenAI Python SDK
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="not-needed", # auth is not required (any string works)
)
resp = client.chat.completions.create(
model="my-profile",
messages=[{"role": "user", "content": "Hello"}],
stream=False,
)
print(resp.choices[0].message.content)
OpenAI-compatible streaming (Python)
stream = client.chat.completions.create(
model="my-profile",
messages=[{"role": "user", "content": "Write one haiku"}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta.content:
print(delta.content, end="", flush=True)
Ollama-compatible (curl / NDJSON)
curl -N http://localhost:11434/api/chat -d '{
"model": "my-profile",
"messages": [{"role": "user", "content": "Introduce yourself"}]
}'
JavaScript (fetch / SSE)
const res = await fetch("http://localhost:11434/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "my-profile",
messages: [{ role: "user", content: "Hello" }],
stream: true,
}),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
for (const line of decoder.decode(value).split("\n")) {
if (!line.startsWith("data: ")) continue;
const data = line.slice(6);
if (data === "[DONE]") break;
const json = JSON.parse(data);
process.stdout.write(json.choices[0].delta.content ?? "");
}
}
This page is based on the current Android implementation (OllamaApiServer). Response examples are formatted for clarity; actual field sets and defaults may vary by app version.