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

# Spend controls

> Set a per-request maximum while preserving intelligent routing and fallbacks.

Pass `routing.max_cost_usd` to reject routes whose published execution envelope exceeds your request budget. Keep the model decision explicit with `model` or `models`; use `ninja/auto` when you want NinjaChat to choose.

<CodeGroup>
  ```typescript TypeScript SDK theme={null}
  const response = await client.responses.create({
    model: "ninja/auto",
    input: "Translate to Spanish: Hello world",
    max_output_tokens: 80,
    routing: {
      strategy: "cost",
      max_cost_usd: 0.005,
      allow_fallbacks: true,
    },
  });

  console.log(response.cost_usd, response.routing.resolved_model);
  ```

  ```python Python SDK theme={null}
  response = client.responses.create(
      model="ninja/auto",
      input="Translate to Spanish: Hello world",
      max_output_tokens=80,
      routing={"strategy": "cost", "max_cost_usd": 0.005, "allow_fallbacks": True},
  )
  ```

  ```bash cURL theme={null}
  curl https://www.ninjachat.ai/api/v1/responses \
    -H "Authorization: Bearer $NINJACHAT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"model":"ninja/auto","input":"Translate to Spanish: Hello world","routing":{"strategy":"cost","max_cost_usd":0.005}}'
  ```
</CodeGroup>

## Parameters

| Parameter              | Description                                                                                                        |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `routing.max_cost_usd` | Maximum allowed cost in US dollars for the routed execution. Positive, up to `1000`.                               |
| `routing.strategy`     | Use `cost` to prefer the least expensive eligible model (with `ninja/auto`) or rail (with a pinned model).         |
| `max_output_tokens`    | Bound generated output and therefore the largest variable part of token spend — and of the pre-authorization hold. |

## How the cap is enforced

1. **Before any provider call**, the gateway computes the maximum token hold for the request: your input estimate plus the output ceiling, priced at the candidate models' metered rates. If that hold is above `max_cost_usd`, the request is rejected with `400 max_cost_exceeded` and nothing runs:

   ```json theme={null}
   {
     "error": {
       "message": "The maximum token hold is $0.012000, above routing.max_cost_usd=$0.005000.",
       "type": "invalid_request_error",
       "code": "max_cost_exceeded",
       "param": "routing.max_cost_usd"
     },
     "maximum_hold_usd": 0.012
   }
   ```

   Lower `max_output_tokens`, pick cheaper candidates, or raise the cap.

2. **At settle time**, the metered charge is capped at `max_cost_usd`. Usage priced above the cap is absorbed by NinjaChat — it is logged, never billed to you.

<Note>
  The cap is a guardrail, not a prediction of the final charge. Actual billing uses measured tokens and is returned as `cost_usd`. Read [live model pricing](/pricing) when you need to forecast a workload.
</Note>

## Where it shines

Cost control per request without maintaining a model list. A tiered product can map plan → budget — treat these as starting points, not guarantees: a plan's real headroom still depends on how long its users' messages run.

```python Python SDK theme={null}
BUDGETS = {"free": 0.005, "pro": 0.05, "enterprise": 0.50}  # USD per request

def chat_for(plan: str, message: str):
    return client.responses.create(
        model="ninja/auto",
        input=message,
        routing={"strategy": "cost", "max_cost_usd": BUDGETS[plan]},
    )
```

As new models and rails launch, `ninja/auto` can improve without changing your integration while the cap remains fixed.
