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

Ollama-compatible OpenAI-compatible SSE / NDJSON streaming Multimodal Tools / Function Calling

Contents

1. Basics

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.

CategoryDetails
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-compatibleGET /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

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
  }
}
StatusMeaning
400Invalid JSON, missing required fields, unsupported content[].type, unsupported modality, etc.
404Unknown route
405Unsupported HTTP method
500Configuration load failure, generation failure, etc.
503Busy (queue full / wait timeout / reset in progress)

4. POST/api/generate

Single-prompt generation (Ollama generate compatible). Streaming (NDJSON) by default.

Request

FieldTypeDescription
modelstringProfile name. Defaults to "default".
promptstringUser prompt.
systemstring?Optional system prompt (overrides the configured one).
streamboolDefault true. Use false for a single response.
toolsarray?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

FieldTypeDescription
modelstringProfile name. Defaults to "default".
messagesarrayRequired. Array of {role, content}. role is system / user / assistant / tool. content is a string, or an array for multimodal input (section 11).
streamboolDefault true.
toolsarray?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

FieldTypeDescription
modelstringProfile name. If empty/omitted, resolves to the currently loaded model, otherwise the default profile.
messagesarrayRequired. OpenAI format. content is a string or an array of {type, ...} parts (section 11).
streamboolDefault true.
tools / tool_choice / parallel_tool_callsarray / any / boolOptional (section 12).
Sampling fieldsnumber, 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.

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).

KeyTypeMaps to
temperaturenumberTemperature
top_kintTop-k
top_pnumberTop-p
min_pnumberMin-p
typ_pnumberTypical-p
dynatemp_range / dynatemp_exponentnumberDynamic temperature
xtc_probability / xtc_thresholdnumberXTC sampler
repeat_last_nintPenalty window size
repeat_penaltynumberRepeat penalty
presence_penalty / frequency_penaltynumberPresence / Frequency penalty
dry_multiplier / dry_base / dry_allowed_length / dry_penalty_last_nnumber / intDRY sampler
mirostat / mirostat_tau / mirostat_etaint / numberMirostat

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.

typeDescription
text / input_textText (text field).
image_urlimage_url.url is an HTTP/HTTPS image URL or a data:image/...;base64, data URL. Remote fetch is limited to 10 MB.
input_audioinput_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.

// 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.