C.W.K.
Stream
Lesson 04 of 05 · published

Model Management Endpoints

~16 min · api, management

Level 0Downloader
0 XP0/41 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Programmatic control of the local fleet

You can do everything ollama the CLI does over HTTP. That matters when you're running Ollama on a remote machine, integrating it into a deploy pipeline, or building UI on top of it.

What each endpoint does

  • GET /api/tags — list installed models with size and modification time.
  • POST /api/show — full metadata, template, parameters, capabilities for one model.
  • POST /api/pull — download a model. Streams NDJSON progress events.
  • DELETE /api/delete — remove a model.
  • POST /api/embed — generate embeddings (single or batch).
  • POST /api/copy — alias / rename a model (cheap, blobs are shared).
  • GET /api/ps — currently loaded models with VRAM usage and TTL.
  • GET /api/version — daemon version (use as health check).

Pull progress is streaming NDJSON

Most management endpoints are non-streaming, but /api/pull emits NDJSON progress lines: {"status": "pulling manifest"}, then {"status": "pulling abc123", "completed": 1234567, "total": 5000000000}, etc. Build a progress bar by reading completed / total per line.

Loading and unloading via API

There's no dedicated load/unload endpoint. The pattern is: send a /api/generate request with empty prompt and keep_alive set, which forces a load. Set keep_alive: 0 on the same endpoint to unload. This is how warmup scripts work.

Code

Force-load and unload programmatically·python
import httpx

OLLAMA = "http://localhost:11434"

def load(model: str, keep_alive: str = "30m"):
    """Force-load a model into memory."""
    httpx.post(f"{OLLAMA}/api/generate",
               json={"model": model, "keep_alive": keep_alive},
               timeout=120.0).raise_for_status()

def unload(model: str):
    """Unload a model from memory immediately."""
    httpx.post(f"{OLLAMA}/api/generate",
               json={"model": model, "keep_alive": 0},
               timeout=10.0).raise_for_status()

def loaded() -> list[dict]:
    """What's loaded right now."""
    return httpx.get(f"{OLLAMA}/api/ps").json().get("models", [])

# Warmup pattern
load("qwen2.5:7b")
print(loaded())   # qwen2.5:7b should appear with size_vram and expires_at
Pull with progress·python
import httpx, json

with httpx.stream("POST", f"{OLLAMA}/api/pull",
                  json={"model": "gemma3:12b"},
                  timeout=None) as r:
    last_status = ""
    for line in r.iter_lines():
        if not line:
            continue
        evt = json.loads(line)
        status = evt.get("status", "")
        if "total" in evt and "completed" in evt:
            pct = 100 * evt["completed"] / max(evt["total"], 1)
            print(f"\r{status}: {pct:5.1f}%", end="", flush=True)
        elif status != last_status:
            print(f"\n{status}", end="")
            last_status = status

External links

Exercise

Write load_warm(model) and unload(model) functions plus a loaded() reader. Use them to write a warm-up script that loads two models in parallel, prints the expires_at for each, then unloads both. Verify with ollama ps between steps.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.