Develop / Guides

Budgets per key

How to give each application its own spending limit, when it resets and how your code responds to status code 402.

A budget limits what an API key may spend in euros. Once it is used up, the gateway rejects further requests from this key with 402. Other keys of your organisation keep working.

  1. Create one key per application

    Create a separate key for each application and each environment, for example chatbot-production and chatbot-test. A budget then affects exactly one application, and the usage per key shows which application causes which costs.

    Admins of your organisation create keys under Models → API keys with New key.

    Result: each application has its own key.

  2. Set the budget

    When you create the key, or later through Details & edit, enter two values in the Budget section:

    • Spending limit (€): the maximum amount, for example €50. Empty means no limit.
    • Reset: Never, Daily, Weekly or Monthly.
    ResetNew period begins
    Dailyevery day at 00:00 UTC
    Weeklyon Mondays at 00:00 UTC
    Monthlyon the 1st of the month at 00:00 UTC
    Nevernever; the limit applies to the entire lifetime of the key

    Result: under Models → API keys, the Usage column shows the amount spent in the current period. Once the limit is reached, it shows Limit reached.

  3. Handle 402

    For status code 402, check the code field in the error object:

    • key_budget_exhausted: this key’s budget is used up for the current period.
    • insufficient_credit: the organisation’s credit is not sufficient. Organisations that pay from credit see this error (see Credit & billing).

    Do not repeat the request unchanged for key_budget_exhausted. Once the limit is reached, it fails until the next reset or until an admin raises the limit. If the message names an estimate (see below), a smaller max_tokens may be enough.

    Result: your application tells an exhausted budget apart from missing credit.

    Shell
    curl -s https://api.noirdoc.de/v1/chat/completions \
      -H "Authorization: Bearer $NOIRDOC_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "qwen3.8-27b",
        "max_tokens": 500,
        "messages": [{"role": "user", "content": "Hello"}]
      }' \
      | jq '.error.code'
    Python
    import os
    import openai
    from openai import OpenAI
    
    client = OpenAI(
        base_url="https://api.noirdoc.de/v1",
        api_key=os.environ["NOIRDOC_API_KEY"],
    )
    
    try:
        response = client.chat.completions.create(
            model="qwen3.8-27b",
            max_tokens=500,
            messages=[{"role": "user", "content": "Hello"}],
        )
    except openai.APIStatusError as e:
        if e.status_code != 402:
            raise
        code = e.response.json()["error"]["code"]
        if code == "key_budget_exhausted":
            ...  # pause until the reset
        elif code == "insufficient_credit":
            ...  # ask admins to top up
    TypeScript
    import OpenAI from "openai";
    
    const client = new OpenAI({
      baseURL: "https://api.noirdoc.de/v1",
      apiKey: process.env.NOIRDOC_API_KEY,
    });
    
    try {
      await client.chat.completions.create({
        model: "qwen3.8-27b",
        max_tokens: 500,
        messages: [{ role: "user", content: "Hello" }],
      });
    } catch (err) {
      if (!(err instanceof OpenAI.APIError)) throw err;
      if (err.status !== 402) throw err;
      if (err.code === "key_budget_exhausted") {
        // pause until the reset
      } else if (err.code === "insufficient_credit") {
        // ask admins to top up
      }
    }

What the budget counts

The budget counts two types of cost:

  • Managed models: requests to priced models managed by Noirdoc.
  • Noirdoc Shield (€0.40 per 1M inspected input tokens): the flat fee across all five protection filters counts towards the key budget (as well as any request tag budgets) whenever Noirdoc Shield inspects text – on Chat, Responses, Messages, Embeddings and Rerank, on requests blocked with 403 shield_violation, and on the standalone inspection endpoint POST /v1/shield/inspect.

On requests routed through your own provider keys (BYOK), model tokens remain unbilled by Noirdoc. When Noirdoc Shield is active on a BYOK request, however, the Shield inspection fee (€0.40 per 1M input tokens) is billed against your organisation’s credit (or invoice) and counts towards API key and request tag budgets. Without active Shield, BYOK calls remain €0 at Noirdoc. Legacy masking for pre-existing organisations remains €0 until its sunset on 30.11.2026.

The gateway books the cost of a request to the key after inspection or after the response.

Check before the request

Before processing, the gateway estimates the highest possible cost of a request:

  • Input: the length of the input fields (such as messages, system prompt, tool definitions) as JSON in characters, divided by 4, as tokens – plus €0.40 per 1M input tokens when Noirdoc Shield is active (including on BYOK routes and on POST /v1/shield/inspect).
  • Output: the value from max_tokens, max_completion_tokens or max_output_tokens. If it is missing, the gateway calculates with 4,096 tokens.

For images, it estimates the number times the price per image or megapixel. If previous usage plus the estimate exceeds the spending limit, the gateway answers with 402 key_budget_exhausted. The message names the estimate and the remaining budget. Set max_tokens to suit your application, so that short requests still go through shortly before the limit.

For audio endpoints, the gateway checks without an estimate whether the limit has already been reached.

JSON
{
  "error": {
    "type": "insufficient_quota",
    "code": "key_budget_exhausted",
    "message": "This request could cost up to 0.42 EUR, more …",
    "param": null
  }
}

Errors

Status Code Meaning
402 insufficient_credit The organisation's credit is used up or lower than the estimated maximum cost of the request (including Noirdoc Shield, also on BYOK routes when Shield is active).
402 key_budget_exhausted This key's budget is used up for the current period or does not cover the estimated cost of the request.