Develop

Quickstart

How to send your first request with an API key, protect inputs with Noirdoc Shield and read the answering provider from the response.

The gateway is available at https://api.noirdoc.de/v1 and speaks the format of the OpenAI API. You need access to the Noirdoc portal and curl, Python or Node.js.

  1. Create a key

    Sign in to the portal; without an account, the page takes you through registration via Create an account. Self-registration requires a connection from the EU or EFTA without a VPN, Private Relay, proxy or data centre IP. When you first sign in, the Getting started page guides you through the setup. Answer the question on § 203 German Criminal Code (StGB) there first, then create your first key. Your answer on § 203 StGB determines which providers are available to your organisation (see Professional secrecy).

    You create further keys under Models → API keys with New key. The portal shows a key once, right after it is created.

    Store the key in an environment variable. All examples in this documentation read it from NOIRDOC_API_KEY. The value starts with px-.

    Result: the environment variable NOIRDOC_API_KEY contains your key.

    Shell
    export NOIRDOC_API_KEY="px-..."
  2. Choose a model

    GET /v1/models lists the models your key may call. Each item in the list has an id. You use this model ID as model in requests.

    The examples use qwen3.8-27b. If this ID is not in your list, use another model ID from the list.

    Result: you know a model ID that your key may call.

    Shell
    curl https://api.noirdoc.de/v1/models \
      -H "Authorization: Bearer $NOIRDOC_API_KEY"
  3. Send your first request

    Send a request to POST /v1/chat/completions. In the OpenAI SDK, set base_url to https://api.noirdoc.de/v1 and api_key to your key.

    Result: the response has the format of the OpenAI API. The text is in choices[0].message.content.

    Shell
    curl https://api.noirdoc.de/v1/chat/completions \
      -H "Authorization: Bearer $NOIRDOC_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "qwen3.8-27b",
        "messages": [{"role": "user", "content": "Hello"}]
      }'
    Python
    import os
    from openai import OpenAI
    
    client = OpenAI(
        base_url="https://api.noirdoc.de/v1",
        api_key=os.environ["NOIRDOC_API_KEY"],
    )
    
    response = client.chat.completions.create(
        model="qwen3.8-27b",
        messages=[{"role": "user", "content": "Hello"}],
    )
    print(response.choices[0].message.content)
    TypeScript
    import OpenAI from "openai";
    
    const client = new OpenAI({
      baseURL: "https://api.noirdoc.de/v1",
      apiKey: process.env.NOIRDOC_API_KEY,
    });
    
    const response = await client.chat.completions.create({
      model: "qwen3.8-27b",
      messages: [{ role: "user", content: "Hello" }],
    });
    console.log(response.choices[0].message.content);
  4. Protect a request with Noirdoc Shield

    Send the X-Noirdoc-Shield: on header. Noirdoc Shield inspects the inbound request statelessly before it reaches the model: by default, it redacts personal data with markers such as [PERSON] and blocks detected secrets and prompt injections with status code 403 (shield_violation). Responses are not reverse-translated.

    You send

    Reply to the email from Jonas Becker.

    The model sees

    Reply to the email from [PERSON].

    New organisations start with the default setting default_off: Shield inspects a request when it sends the header with on or when the API key or request tag enables Shield. All settings are described in Set up Noirdoc Shield.

    Result: the model receives sanitised input without the redacted original values, and the response reports the inspection outcome in the X-Noirdoc-Shield header.

    Shell
    curl https://api.noirdoc.de/v1/chat/completions \
      -H "Authorization: Bearer $NOIRDOC_API_KEY" \
      -H "Content-Type: application/json" \
      -H "X-Noirdoc-Shield: on" \
      -d '{
        "model": "qwen3.8-27b",
        "messages": [{
          "role": "user",
          "content": "Reply to the email from Jonas Becker."
        }]
      }'
    Python
    response = client.chat.completions.create(
        model="qwen3.8-27b",
        messages=[{
            "role": "user",
            "content": "Reply to the email from Jonas Becker.",
        }],
        extra_headers={"X-Noirdoc-Shield": "on"},
    )
    print(response.choices[0].message.content)
    TypeScript
    const response = await client.chat.completions.create(
      {
        model: "qwen3.8-27b",
        messages: [
          {
            role: "user",
            content: "Reply to the email from Jonas Becker.",
          },
        ],
      },
      { headers: { "X-Noirdoc-Shield": "on" } },
    );
    console.log(response.choices[0].message.content);
  5. Read the provider from the response

    In curl, -i shows the headers. In the SDKs you read headers from the raw response. The rule by which the gateway picks the provider is described in Providers & routing.

    Result: the response contains the X-Noirdoc-Provider header. It names the provider that answered the request.

    Shell
    curl -i https://api.noirdoc.de/v1/chat/completions \
      -H "Authorization: Bearer $NOIRDOC_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "qwen3.8-27b",
        "messages": [{"role": "user", "content": "Hello"}]
      }'
    Python
    raw = client.chat.completions.with_raw_response.create(
        model="qwen3.8-27b",
        messages=[{"role": "user", "content": "Hello"}],
    )
    print(raw.headers.get("x-noirdoc-provider"))
    response = raw.parse()
    TypeScript
    const { data, response } = await client.chat.completions
      .create({
        model: "qwen3.8-27b",
        messages: [{ role: "user", content: "Hello" }],
      })
      .withResponse();
    console.log(response.headers.get("x-noirdoc-provider"));

Troubleshooting

Every error response from the gateway has an error object with type, code and message. A missing or invalid key results in status code 401 with the code invalid_api_key. These codes are the most common when getting started:

Status Code Meaning
400 model_required The request names no model (model in the body, or in the form field for /v1/audio/transcriptions).
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).
403 model_not_allowed_for_key The model is not one of this key's allowed models.
403 starter_model_not_allowed The organisation is still using only its starter credit, and the model or its managed provider is not included in starter credit.
403 shield_violation Noirdoc Shield blocked the request before forwarding to the provider because an active protection filter configured with block matched; message names the triggered rule (secrets, pii, ner, injection or custom).
404 model_not_available The model ID is not available to the organisation.
429 starter_rate_limit_exceeded The organisation is still using only its starter credit and has reached the limit of 5 requests per minute or 25 requests per day (UTC) for managed providers. The response contains Retry-After with the wait in seconds.

All codes are listed under Error codes.

Next steps