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

# How the gateway works

> One key, your own providers, and the endpoints Nemu exposes

Nemu sits between your application and the model providers you have connected.
You send one gateway key; Nemu resolves the model, picks the provider
credential, applies your mappings, quotas and budgets, records the request, and
forwards it upstream. Provider keys never leave the console.

## Base URLs

| Protocol           | Base URL                        | Main endpoint       |
| ------------------ | ------------------------------- | ------------------- |
| OpenAI-compatible  | `https://api.nemu.cc/v1`        | `/chat/completions` |
| OpenAI Responses   | `https://api.nemu.cc/v1`        | `/responses`        |
| Anthropic Messages | `https://api.nemu.cc/anthropic` | `/v1/messages`      |

Anthropic clients append `/v1/messages` to whatever base URL you give them, so
`https://api.nemu.cc` works as an Anthropic base URL too: both
`https://api.nemu.cc/v1/messages` and `https://api.nemu.cc/anthropic/v1/messages`
serve the Messages API.

## Authentication

Send the gateway key either way. Anthropic clients tend to use `x-api-key`,
OpenAI clients use the bearer header, and Nemu accepts both on every endpoint.

```bash theme={null}
curl https://api.nemu.cc/v1/chat/completions \
  -H "Authorization: Bearer YOUR_NEMU_GATEWAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"openrouter/nemotron","messages":[{"role":"user","content":"hi"}]}'
```

Keys are created in the console and look like `sk_xxxxx-xxxxx.` followed by a
40 character secret. A key belongs to one workspace and can only reach the
providers and models enabled in that workspace.

## Endpoints

| Method | Path                                  | What it does                                  |
| ------ | ------------------------------------- | --------------------------------------------- |
| POST   | `/v1/chat/completions`                | Chat completions, streaming or buffered       |
| POST   | `/v1/responses`                       | OpenAI Responses API                          |
| POST   | `/v1/embeddings`                      | Embeddings                                    |
| POST   | `/v1/images/generations`              | Image generation                              |
| POST   | `/v1/moderations`                     | Moderation                                    |
| POST   | `/v1/audio/speech`                    | Text to speech                                |
| POST   | `/v1/audio/transcriptions`            | Speech to text                                |
| POST   | `/v1/audio/translations`              | Speech to English text                        |
| POST   | `/v1/count_tokens`                    | Token count for an OpenAI-shaped request      |
| GET    | `/v1/models`                          | Models enabled for the key's workspace        |
| POST   | `/anthropic/v1/messages`              | Anthropic Messages, streaming or buffered     |
| POST   | `/anthropic/v1/messages/count_tokens` | Anthropic token count                         |
| GET    | `/anthropic/v1/models`                | The same models, in Anthropic's shape         |
| GET    | `/reader`                             | Fetch a URL as clean text, metered in credits |
| GET    | `/health`                             | Liveness, no key required                     |

## Choosing a model

`GET /v1/models` returns exactly the strings you can put in `model`. Each one is
the model's **gateway name**: the provider name, a slash, and the alias you gave
it in the console.

```json theme={null}
{
  "object": "list",
  "data": [
    { "id": "openrouter/nemotron", "object": "model", "owned_by": "openrouter" }
  ]
}
```

For models added from the models.dev catalog, the gateway name is yours to
choose and is independent of the upstream model id, so `openrouter/nemotron` can
point at `nvidia/nemotron-nano-9b-v2` upstream. Edit it under **Models** in the
console.

The gateway name is the only model name a client may send. The upstream id is
not accepted, so nothing you run can address a provider model that you have not
deliberately exposed, and renaming a model in the console changes the name your
clients use without touching the provider.

Two other values are accepted in `model`:

* **A mapping.** Mappings match a pattern and rewrite it to a gateway name, which
  is how you keep a client that hardcodes `gpt-4o` pointed at whatever you want.
* **`auto`.** When automatic routing is configured, Nemu picks the model.

### Variants

A gateway name can carry a variant in square brackets, the way some clients write
`claude-opus-5[1m]`. The variant is stripped before the model is resolved, so
`openrouter/nemotron[1m]` addresses `openrouter/nemotron`. `[1m]` asks for a
one million token context: it raises the accounted context window and, for
Anthropic providers, sends the `context-1m-2025-08-07` beta header upstream.

## Compatibility

Nemu speaks three wire protocols on the way in and translates to whatever the
upstream provider speaks. An Anthropic-shaped request can be served by an
OpenAI-compatible provider and the other way round: system blocks, tool calls,
streaming events, thinking blocks and cache breakpoints are converted in both
directions.

Reasoning is handled per model. Anthropic-style `thinking` budgets, OpenAI-style
`reasoning_effort` and adaptive modes are mapped to whatever the target model
actually supports, so a request that asks for thinking on a model without it
succeeds instead of failing with a 400.

## Errors

Every error says which side failed. The `x-nemu-error-origin` response header is
`nemu` when the gateway stopped the request and `provider` when the upstream did,
so a 402 from your provider's billing is never confused with a 402 from your
nemu budget.

```json theme={null}
{
  "error": {
    "message": "Model openrouter/nemotron does not exist or you do not have access to it.",
    "type": "model_not_found",
    "code": "model_not_found"
  }
}
```

Anthropic endpoints return Anthropic's `{"type":"error","error":{...}}` shape
with the matching `invalid_request_error`, `authentication_error`,
`not_found_error`, `rate_limit_error` or `overloaded_error` type.

Errors that the gateway itself raised end with a reference, as in
`... (id: 6f1c2a9e-...)`. That is the id of the request's row under **Metrics**,
so a report can be traced to the exact request without guessing.

## Limits and accounting

Requests are counted against your plan and against any quota rules and monthly
budget set for the workspace. A 429 carries `Retry-After` and the limit that was
hit, so a client can pace itself instead of guessing.

Request bodies are capped per plan, which matters for coding agents because the
whole conversation is resent every turn:

| Plan       | Maximum request body |
| ---------- | -------------------- |
| Free       | 2 MB                 |
| Starter    | 4 MB                 |
| Pro        | 8 MB                 |
| Max        | 16 MB                |
| Enterprise | 32 MB                |

Going over returns a 413 naming both the size sent and the limit.

Every request lands in **Metrics** with its model, provider, latency, token
counts, cost and origin. Requests that came from nemu's own chat are labelled as
such rather than showing an internal address.

## Caching

Providers, models, mappings, prompts and quota rules are cached for speed.
Changing any of them in the console or through the management API clears the
gateway's copy immediately, so a rotated provider key takes effect on the next
request.
