The shape
/api/chat takes a messages array (system / user / assistant / tool roles) and returns either streaming NDJSON or a single JSON object depending on stream. This is the endpoint you'll use for everything except raw completion / FIM.
Request fields
model(required) — the model name as it appears inollama list.messages— array of{role, content, images?, tool_calls?}. Roles:system,user,assistant,tool.stream— boolean (defaulttrue).format—"json"or a JSON Schema object for structured outputs.options— inference parameters (temperature,top_p,num_ctx,num_predict, ...).tools— array of OpenAI-format tool definitions for function calling.keep_alive— how long the model stays loaded after this request (default"5m"; set"-1"to pin).think— boolean; enables thinking output for reasoning models that support it.
Response fields (non-streaming)
message—{role, content, tool_calls?}.done— boolean (alwaystruewhen stream is off).- Timing:
total_duration,load_duration,prompt_eval_count,prompt_eval_duration,eval_count,eval_duration— all in nanoseconds.
Why prefer /api/chat over /api/generate
The messages shape forces you to think about role boundaries (system instructions vs user turns vs assistant outputs vs tool results). That structure is what makes tool use, multi-turn context, and the adapter pattern coherent later. /api/generate looks simpler but pushes you toward concatenated-string prompts that are harder to compose.