> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ninjachat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat

> Send messages to any model and get a response with its exact cost.

The one endpoint behind everything: pick a model (or say `auto`), send messages, get the answer and the price.

```json POST /api/v1/chat theme={null}
{
  "model": "gpt-5",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Explain quantum computing in one paragraph."}
  ]
}
```

```json Response theme={null}
{
  "model": "gpt-5",
  "choices": [{
    "message": {"role": "assistant", "content": "Quantum computing harnesses..."},
    "finish_reason": "stop"
  }],
  "usage": {"prompt_tokens": 24, "completion_tokens": 87, "total_tokens": 111},
  "cost": {"this_request": "$0.0010"},
  "balance": "$4.820",
  "metadata": {"latency_ms": 1243}
}
```

## Parameters

| Parameter               | Type             | Default      | Description                                                                                                                                                                       |
| ----------------------- | ---------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`                 | string           | `ninja-1`    | A [model ID](/models), an [`auto` variant](/smart-routing), an [ensemble](/ensemble), or a [fallback chain](/fallback-chains) like `"a>b>c"`.                                     |
| `messages`              | array            | required     | 1–50 messages of `{role, content}` — roles are `system`, `user`, `assistant`. `content` is a string, or an array of `text` / `image_url` parts for [vision input](#vision-input). |
| `temperature`           | number           | `0.7`        | 0 = deterministic, 2 = creative.                                                                                                                                                  |
| `max_tokens`            | integer          | `2048`       | Max response length (1–16,384).                                                                                                                                                   |
| `max_completion_tokens` | integer          | —            | OpenAI alias for `max_tokens`. Takes precedence if both are set.                                                                                                                  |
| `top_p`                 | number           | —            | Nucleus sampling (0–1).                                                                                                                                                           |
| `stop`                  | string or array  | —            | Up to 4 stop sequences.                                                                                                                                                           |
| `frequency_penalty`     | number           | —            | -2 to 2. Penalizes tokens by how often they've already appeared.                                                                                                                  |
| `presence_penalty`      | number           | —            | -2 to 2. Penalizes tokens that have appeared at all.                                                                                                                              |
| `seed`                  | integer          | —            | Best-effort deterministic sampling seed.                                                                                                                                          |
| `n`                     | integer          | `1`          | Only `n=1` is supported.                                                                                                                                                          |
| `user`                  | string           | —            | Opaque end-user identifier for your own tracking (max 256 chars).                                                                                                                 |
| `response_format`       | object           | —            | `{"type": "text" \| "json_object"}`.                                                                                                                                              |
| `stream_options`        | object           | —            | `{"include_usage": boolean}`. Only relevant when `stream: true`.                                                                                                                  |
| `stream`                | boolean          | `false`      | Token-by-token SSE — [Streaming](/streaming).                                                                                                                                     |
| `session_id`            | string           | —            | Server-side conversation memory — [Sessions](/sessions).                                                                                                                          |
| `cache`                 | boolean          | `true`       | Identical requests return instantly at no cost — see [Caching](#caching) below for the full list of conditions that disable it.                                                   |
| `include_quality`       | boolean          | `false`      | Include a `quality` confidence score in the response — [Quality Scoring](/quality-scoring).                                                                                       |
| `include_routing`       | boolean          | `false`      | Include a `routing` object describing how `auto` resolved.                                                                                                                        |
| `budget_cents`          | number           | —            | Auto-select the best model at or under this cost (0.1–100 cents). Overrides `model` entirely — [Budget Routing](/budget-routing).                                                 |
| `min_quality`           | number           | —            | Minimum quality threshold (0–1). If the response scores below it, auto-retry with a better model — [Fallback Chains](/fallback-chains).                                           |
| `fallback_on_error`     | boolean          | `true`       | With a fallback chain, continue to the next model on error.                                                                                                                       |
| `fallback_strategy`     | string           | `sequential` | `sequential`, `parallel-race` (first quality response wins), or `parallel-best` (highest quality after all complete) — [Fallback Chains](/fallback-chains).                       |
| `tools`                 | array            | —            | OpenAI-style function definitions, up to 32 — see [Function calling](#function-calling).                                                                                          |
| `tool_choice`           | string or object | —            | `"auto"`, `"none"`, `"required"`, or `{"type": "function", "function": {"name": "..."}}`.                                                                                         |
| `route_mode`            | string           | `smart`      | `smart` or `fast` — controls how much analysis `auto` does before picking a model.                                                                                                |

## Multi-turn

Two ways to carry a conversation:

<Tabs>
  <Tab title="Sessions (recommended)">
    Send only the new message — NinjaChat stores and injects history server-side for 7 days.

    ```json theme={null}
    {
      "model": "gpt-5",
      "messages": [{"role": "user", "content": "What did I just ask you?"}],
      "session_id": "user-alice-1"
    }
    ```

    [Sessions →](/sessions)
  </Tab>

  <Tab title="Manual history">
    Pass the full conversation every request:

    ```json theme={null}
    {
      "model": "gpt-5",
      "messages": [
        {"role": "user", "content": "What is photosynthesis?"},
        {"role": "assistant", "content": "Photosynthesis converts sunlight..."},
        {"role": "user", "content": "How does it compare to solar panels?"}
      ]
    }
    ```
  </Tab>
</Tabs>

## Vision input

Any [vision-capable model](/models) accepts images by sending `content` as an array of parts instead of a plain string — mix `text` and `image_url` parts in one message:

```json theme={null}
{
  "model": "gpt-5",
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "What's in this image?"},
        {"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg", "detail": "auto"}}
      ]
    }
  ]
}
```

`image_url.url` accepts a public HTTPS URL or a base64 data URL. `detail` is optional (`auto`, `low`, or `high`). Sending images to a model that isn't vision-capable returns a `model_not_vision_capable` error listing which models support it.

## Function calling

Pass OpenAI-style `tools` and NinjaChat routes the model's tool calls back to you the same way OpenAI does — the model doesn't execute anything itself, it just tells you what to call:

```json theme={null}
{
  "model": "gpt-5",
  "messages": [{"role": "user", "content": "What's the weather in Austin?"}],
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get the current weather for a city",
      "parameters": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
      }
    }
  }],
  "tool_choice": "auto"
}
```

Only [tool-capable models](/models) accept `tools` — passing them to a model that doesn't support tool calling returns a `model_not_tool_capable` error.

## Caching

`cache: true` (the default) returns identical requests instantly at no cost. Caching is automatically disabled — the request always runs live — when any of these are true:

* `session_id` is set (history changes every turn)
* `stream: true`
* `model` is a fallback chain (`"a>b>c"`)
* `model` is an ensemble variant (`ensemble`, `ensemble-quality`)
* Any message contains image content
* `tools` is set
* `temperature` is above `0.3`

## The model field is a superpower

Everything else about the request stays the same — only `model` changes:

| `model` value                                     | Behavior                                                              |
| ------------------------------------------------- | --------------------------------------------------------------------- |
| `"gpt-5"`                                         | That exact model                                                      |
| `"auto"`                                          | Best model for this prompt — [Smart Routing](/smart-routing)          |
| `"auto-fast"` / `"auto-cheap"` / `"auto-quality"` | Routing biased to latency / cost / quality                            |
| `"claude-opus-4.6>gpt-5>gemini-3.1-pro"`          | Try in order until one succeeds — [Fallback Chains](/fallback-chains) |
| `"ensemble"`                                      | 3 models answer, a 4th synthesizes — [Ensemble](/ensemble)            |

<Tip>
  Try any of these live in the [Playground](https://www.ninjachat.ai/developers/playground) — every run shows the exact request that made it.
</Tip>
