Develop / Guides

Files

How to send files to models, which file parts Noirdoc Shield inspects and what happens when you upload through /v1/files.

Files reach a model in two ways:

  • Inline in the body: as a Base64 data: URL in a message to /v1/chat/completions, /v1/responses or /v1/messages. Noirdoc Shield can decode and inspect inline UTF-8 text files.
  • Upload through /v1/files: the gateway passes the file to the provider unchanged. Messages then refer to it by file_id.

Allow file and image attachments

Under Models → Shield in Advanced Settings, the Allow file and image attachments in requests (allow_file_content) switch is on by default. If it is off, the gateway rejects these requests with 403 file_content_not_allowed:

  • Messages with file, image or audio parts, including with a file_id reference
  • All requests to /v1/files and /v1/skills
  • Transcriptions through /v1/audio/transcriptions

Send files inline

When Noirdoc Shield is active for a request to /v1/chat/completions, /v1/responses or /v1/messages, the gateway distinguishes between inline UTF-8 text files and binary or referenced content (details on the inspected fields under Inspected fields):

  • Inline UTF-8 text files: Shield decodes inline UTF-8 files (text/*, JSON, XML, CSV, Markdown and YAML under 4 MiB decoded) before forwarding, redacting matches or blocking the request with 403 shield_violation according to the active protection filters. If the total text to inspect exceeds 4 MiB, the gateway answers with 413 shield_input_too_large.
  • Binary documents, media and references: Shield cannot inspect binary documents (PDF, DOCX, XLSX, PPTX), images, audio, video or file references via file_id or external URL as text:
    • Under the enforced organisation policy, the gateway rejects such requests before forwarding with 422 shield_uninspectable_content. Extract the text client-side beforehand and send it as message text or an inline UTF-8 text file.
    • Under default_on, a key or tag set to on, or X-Noirdoc-Shield: on (non-enforced), Shield inspects all text fields and inline UTF-8 text files of the request, forwards binary parts and file references untouched, and marks the partial inspection in the response with X-Noirdoc-Shield: partial; redacted=<n> and X-Noirdoc-Masked: false.

Generated files downloaded via GET /v1/files/{id}/content are passed through directly – Shield is stateless and stores no placeholder mappings.

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": [
        {
          "type": "text",
          "text": "Summarise the notes."
        },
        {"type": "file", "file": {
          "filename": "notes.txt",
          "file_data": "data:text/plain;base64,Sm9uYXMg..."
        }}
      ]
    }]
  }'

Upload files

/v1/files passes uploading, retrieving and deleting files through to the provider unchanged. Noirdoc Shield inspects nothing here. The gateway therefore rejects uploads (POST /v1/files) under the enforced policy or with X-Noirdoc-Mask: on with 403 masking_not_supported_for_endpoint (otherwise it forwards the upload uninspected). Listing, retrieving, downloading and deleting remain allowed.

The header that carries your key determines the provider:

  • Authorization: Bearer or api-key: Files API in the OpenAI format
  • x-api-key (Anthropic SDK): Anthropic’s Files API. The gateway adds the required anthropic-beta value.

With X-Provider: anthropic, you choose Anthropic even with Authorization: Bearer.

Shell
curl https://api.noirdoc.de/v1/files \
  -H "Authorization: Bearer $NOIRDOC_API_KEY" \
  -F purpose="user_data" \
  -F file="@contract.pdf"
Python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.noirdoc.de/v1",
    api_key=os.environ["NOIRDOC_API_KEY"],
)

uploaded = client.files.create(
    file=open("contract.pdf", "rb"), purpose="user_data"
)
print(uploaded.id)
TypeScript
import fs from "node:fs";
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.noirdoc.de/v1",
  apiKey: process.env.NOIRDOC_API_KEY,
});

const uploaded = await client.files.create({
  file: fs.createReadStream("contract.pdf"),
  purpose: "user_data",
});
console.log(uploaded.id);

Managed providers

With providers managed by Noirdoc, several organisations share one account at the provider. The gateway therefore assigns every uploaded file to your organisation:

  • GET /v1/files lists your organisation’s files.
  • The gateway treats a file_id of another organisation like an unknown one: 404 object_not_found. This also applies to references in messages.

With your own provider (BYOK), this assignment does not apply; there you see your provider’s account.

Skills

/v1/skills passes requests through to Anthropic’s Skills API, also without Shield inspection. The same rule as for /v1/files applies under enforced and X-Noirdoc-Mask: on: the gateway then rejects creating skills and versions with 403 masking_not_supported_for_endpoint. The endpoints are described in detail under Files & Skills.

Legacy file analysis (sunset on 30.11.2026)

For pre-existing organisations still running legacy masking during the transition period until 30.11.2026, the gateway continues to apply file_analysis_mode to inline files when masking is active (including PDF, DOCX, XLSX and text up to the configured maximum size of 25 MB by default, optionally with OCR for scans and images):

  • passthrough (Pass through): forwards the file without inspection.
  • detect_only (Detect only): detects personal data and forwards the file unchanged (rejected with 403 file_pii_blocked under enforced).
  • pseudonymize (Pseudonymize): replaces personal data with placeholders such as <<PERSON_1>> (DOCX, XLSX and text keep their format; PDFs are replaced by their masked text). Text-based downloads via GET /v1/files/{id}/content are re-identified using stored mappings.
  • block (Block): rejects files containing personal data with 403 file_pii_blocked.

If legacy file analysis cannot process a file in the block or pseudonymize modes (size limit exceeded, unreadable or unknown format), the gateway answers with 422 file_unprocessable. Once an organisation switches to Noirdoc Shield under Models → Shield, these modes are replaced by the inline UTF-8 text inspection described above.

Errors

Status Code Meaning
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).
403 masking_not_supported_for_endpoint The endpoint supports neither Noirdoc Shield nor legacy masking, yet the policy is enforced or the request sends X-Noirdoc-Mask: on (and on /v1/images/generations also X-Noirdoc-Shield: on). During the legacy masking transition until 30.11.2026, this also affects /v1/embeddings and /v1/rerank on pre-existing organisations that have not switched to Shield yet.
403 file_content_not_allowed The request contains files, images or audio, and the organisation does not allow file content.
403 file_pii_blocked A file contains personal data, and the organisation's legacy file analysis (transition until 30.11.2026) is set to block or to detect_only under enforced.
404 object_not_found The object (file, skill or stored response) does not exist or does not belong to your organisation.
413 shield_input_too_large The text to inspect in this request exceeds the Shield service limit of 4 MiB of encoded text in a single call.
422 shield_uninspectable_content The Shield policy is enforced, and the request carries content that Shield cannot inspect as text (binary_document such as PDF or Office, media_not_inspectable such as images, audio or video, file_reference by ID or URL, file_too_large at 4 MiB or above, file_not_decodable or unrecognised_content). The gateway did not forward the request.
422 file_unprocessable A file could not be processed in legacy file analysis (transition until 30.11.2026): it is too large, unreadable or in a format without analysis. The gateway did not forward the request.
500 file_analysis_error Reserved for file analysis errors. The gateway does not currently send this code.