Develop / Guides
Request tags (Preview)
How to label requests by matter, cost centre or team with X-Noirdoc-Tags, set per-tag budgets and model restrictions, and manage tags through /v1/tags.
Request tags let you attribute individual requests to a matter, cost centre, team or client of your application through the X-Noirdoc-Tags header – without issuing a separate API key for every matter. Each tag keeps its own usage counters and can carry its own euro budget, its own model and provider restrictions and its own Noirdoc Shield mode (shield_mode).
-
Set up the default tag template or create tags in the portal
Once enabled, admins of your organisation manage tags under Models → Tags.
In the Default tag template section, you define how the gateway handles unknown tag names in the
X-Noirdoc-Tagsheader:- Automatically create unknown tags on first use (default: turned on): when your application sends a new tag, the gateway creates it automatically on the first forwarded request and copies the budget, the model and provider restrictions and
shield_modefrom the template. - Automatic creation turned off: the gateway rejects unknown tags in the
X-Noirdoc-Tagsheader with status code 403 and error codetag_not_found. Create valid tags in advance through New tag or withPOST /v1/tags.
Tag names follow these rules:
- Format: 1 to 64 characters from
a-z,A-Z,0-9and_,.,:and-, starting with a letter or digit (^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,63}$). - Reserved name:
_defaultis reserved for the template endpoint/v1/tags/_defaultand cannot be used as a tag name. - Limit: each organisation can create up to 1,000 request tags (
tag_limit_exceeded).
Result: your organisation has a default tag template or pre-created tags.
- Automatically create unknown tags on first use (default: turned on): when your application sends a new tag, the gateway creates it automatically on the first forwarded request and copies the budget, the model and provider restrictions and
-
Set the budget, restrictions and Noirdoc Shield per tag
For the Default tag template and for each individual tag, you can set the same guardrails as for an API key (see Budgets per key, Restrict models & providers and Set up Noirdoc Shield):
- Spending limit (€) and Reset: Never, Daily (00:00 UTC), Weekly (Mondays at 00:00 UTC) or Monthly (on the 1st of the month at 00:00 UTC). Empty means no separate limit for this tag.
- Noirdoc Shield (
shield_mode): Inherit ("inherit", defers to headers and the organisation default), On ("on", turns Shield on for requests carrying this tag) or Off ("off", turns Shield off unless the organisation policy isenforcedor the API key or another attached tag turns Shield on). - Allowed models: All models or Selected models only.
- Provider restrictions: Data residency, Only providers without CLOUD Act exposure, Only §203-covered providers and a selection of allowed Providers.
Result: under Models → Tags, the table shows the status (Active or Inactive), usage in the current period, total spend and the time of last use for each tag.
-
Send X-Noirdoc-Tags with requests
Pass 1 to 5 comma-separated tag names in the
X-Noirdoc-Tagsheader. If the same tag appears more than once on a request, the gateway deduplicates it. Before forwarding the request to the provider, the gateway strips the header.GET /v1/modelsalso evaluatesX-Noirdoc-Tagsand returns only models permitted for both the key and all named tags. Likewise,POST /v1/shield/inspectacceptsX-Noirdoc-Tagsfor cost attribution and tag budget enforcement.Result: the gateway checks the budget and restrictions of the named tags and books the request to each tag after the response.
curl https://api.noirdoc.de/v1/chat/completions \ -H "Authorization: Bearer $NOIRDOC_API_KEY" \ -H "X-Noirdoc-Tags: mandat-2026-042,team-arbeitsrecht" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3.8-27b", "max_tokens": 500, "messages": [{"role": "user", "content": "Hello"}] }'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", max_tokens=500, messages=[{"role": "user", "content": "Hello"}], extra_headers={ "X-Noirdoc-Tags": "mandat-2026-042,team-arbeitsrecht", }, )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", max_tokens: 500, messages: [{ role: "user", content: "Hello" }], }, { headers: { "X-Noirdoc-Tags": "mandat-2026-042,team-arbeitsrecht", }, }, );
Multiple tags and interaction with the key
When you send one or more tags in X-Noirdoc-Tags, the gateway combines the rules of the organisation, the API key and all named tags:
- Allowed models and providers (intersection): a model and a provider are eligible only if they are permitted for the organisation (§ 203 StGB), for the calling API key and for every attached tag. If any tag excludes the model or all of its providers, the gateway answers with 403
model_not_allowed_for_tagorprovider_not_allowed_for_tag. - Noirdoc Shield (
shield_modeand precedence): whether Shield inspects a request follows the precedence order organisationenforced> API keyshield_mode("on"/"off") > request tagshield_mode>X-Noirdoc-Shieldheader > organisation default (default_on/default_off), see Policy and precedence. When multiple tags are sent inX-Noirdoc-Tags, any"on"among attached tags wins over"off";"inherit"defers to the next level. - Order of budget checks: before forwarding the request, the gateway checks the organisation’s credit first (
insufficient_credit), then the API key’s budget (key_budget_exhausted) and then the budgets of the tags in the order listed inX-Noirdoc-Tags. If a tag’s budget is used up or smaller than the request’s cost estimate, the gateway answers with 402tag_budget_exhausted;messagenames the affected tag. - Full cost booked per tag: after the response or inspection, the gateway books the full cost of the request – priced models managed by Noirdoc as well as the Noirdoc Shield inspection fee (€0.40 per 1M inspected input tokens, including on
POST /v1/shield/inspectand on BYOK routes when Shield is active) – both to the API key and to every tag named inX-Noirdoc-Tags. This lets you track independent dimensions – such as a matter budget (mandat-2026-042) and a department budget (team-arbeitsrecht) – on the same request. As with key budgets, requests through your own providers (BYOK) without active Shield count as €0.
Managing tags via the API (/v1/tags)
Alongside the interface under Models → Tags, you can manage tags and the default tag template through the /v1/tags endpoint – for example automatically when opening a new file in your practice management software.
API key permission
By default, an API key is not allowed to call /v1/tags (403 insufficient_key_permissions). Under Models → API keys, turn on Allow tag management (/v1/tags) when creating or editing the key.
Endpoints at a glance
| Method and path | Effect |
|---|---|
GET /v1/tags | Lists the organisation’s tags (optionally with limit, offset and search filter q). |
POST /v1/tags | Creates a new tag (201 Created). If the name already exists, the gateway answers with 409 tag_already_exists. |
GET /v1/tags/_default | Reads the organisation’s default tag template (tag_auto_create_enabled, shield_mode, budget and restrictions). |
PUT /v1/tags/_default | Updates the organisation’s default tag template. |
GET /v1/tags/{name} | Reads a single tag including shield_mode, current usage (budget_spent_eur), total spend (budget_spent_total_eur) and last_used_at. |
PUT /v1/tags/{name} | Creates the tag or replaces its settings; existing usage counters are preserved. |
PATCH /v1/tags/{name} | Updates individual fields of an existing tag; existing usage counters are preserved. |
DELETE /v1/tags/{name} | Deactivates an active tag or permanently deletes an already inactive tag without spend history (204 No Content). |
When updating via PUT /v1/tags/{name} or PATCH /v1/tags/{name}, budget_spent_eur, budget_spent_total_eur and last_used_at remain unchanged.
DELETE /v1/tags/{name} works in two stages so that billing records are not lost:
- Active tag (
is_active: true): the firstDELETEcall sets the tag tois_active: false(204 No Content). Subsequent requests carrying this tag receive 403tag_disabled. You can reactivate the tag at any time viaPATCH /v1/tags/{name}with{"is_active": true}. - Already inactive tag (
is_active: false): a secondDELETEcall permanently deletes the tag (204 No Content) only if no spend has been recorded on it (budget_spent_total_eur == 0). If spend has already been recorded, the gateway answers with 409tag_has_spend_history.
curl -X PUT https://api.noirdoc.de/v1/tags/mandat-2026-042 \
-H "Authorization: Bearer $NOIRDOC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "Matter 2026/042 – Employment law",
"budget_limit_eur": 25.0,
"budget_reset": "monthly",
"shield_mode": "on",
"allowed_residencies": ["DE", "EU"],
"require_no_cloud_act": true,
"require_section203": true
}'Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request_tags | The X-Noirdoc-Tags header or the tag name in the path under /v1/tags is empty, contains more than 5 tags or does not match the format ^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,63}$. |
| 402 | tag_budget_exhausted | The budget of a tag named in X-Noirdoc-Tags is used up for the current period or does not cover the estimated cost of the request; message names the tag. |
| 403 | request_tags_disabled | The request sends X-Noirdoc-Tags or calls /v1/tags, but request tags (Preview) are not enabled for this organisation. |
| 403 | tag_not_found | The named tag does not exist. On requests with X-Noirdoc-Tags, automatic tag creation is turned off (status code 403); on /v1/tags/{name}, the gateway answers with status code 404. |
| 403 | tag_disabled | A tag named in X-Noirdoc-Tags is deactivated. |
| 403 | tag_limit_exceeded | The organisation has reached the maximum of 1,000 request tags. |
| 403 | insufficient_key_permissions | The API key lacks permission for /v1/tags (can_manage_tags) or /v1/shield/policy (can_manage_shield), a key pinned to shield_mode: on tries to weaken the Shield policy or a tag's shield_mode, or the tag requests broader models, providers or compliance rules than the calling key itself holds. |
| 403 | model_not_allowed_for_tag | The model is not one of the allowed models of a tag named in X-Noirdoc-Tags. |
| 403 | provider_not_allowed_for_tag | The restrictions of a tag named in X-Noirdoc-Tags (providers, data residency, CLOUD Act, § 203) exclude every provider of this model. |
| 409 | tag_already_exists | A tag with this name already exists in the organisation. |
| 409 | tag_has_spend_history | Spend has already been recorded for this tag, so it cannot be permanently deleted. |