Develop / Reference

Audio

Transcribes audio files and generates speech output in the OpenAI format; neither endpoint is inspected by Noirdoc Shield.

Both endpoints accept only POST. The gateway answers other methods with 405 method_not_allowed. Neither endpoint supports streaming.

Transcription

POST /v1/audio/transcriptions
Family
stt
Shield
no
Streaming
no
Format
multipart/form-data
Billing
audio duration

The body is a multipart form, as with the OpenAI Audio API. model is required and must be a model of the stt family from GET /v1/models. The fields model, stream and response_format may each appear only once.

Audio counts as file content. The endpoint works only if admins of your organisation have turned on Allow file and image attachments in requests under Models → Shield (Advanced Settings). Otherwise, the gateway answers with 403 file_content_not_allowed.

The body may be at most 26 MB. The gateway rejects larger requests with 413 request_too_large before forwarding them.

Shell
curl https://api.noirdoc.de/v1/audio/transcriptions \
  -H "Authorization: Bearer $NOIRDOC_API_KEY" \
  -F model=whisper \
  -F file=@dictation.mp3
Python
import os
from openai import OpenAI

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

with open("dictation.mp3", "rb") as audio:
    transcript = client.audio.transcriptions.create(
        model="whisper", file=audio
    )
print(transcript.text)
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 transcript = await client.audio.transcriptions.create({
  model: "whisper",
  file: fs.createReadStream("dictation.mp3"),
});
console.log(transcript.text);

What Noirdoc changes

AreaBehaviour
ModelThe gateway resolves the model ID through the catalogue and uses it to select the provider. It forwards the audio file unchanged.
response_formatWith json, text or no value, the gateway requests verbose_json from the provider so it can bill the audio duration. You receive the format you requested: an object with only text for json, plain text for text. If the provider reports no duration, you receive its verbose_json response unchanged. The gateway passes verbose_json, srt, vtt and other formats through unchanged.
streamIf you set stream to true, 1, yes or on, the gateway answers with 400 streaming_not_supported_for_endpoint.
BillingThe gateway bills by the audio duration that the provider reports in verbose_json.
ProviderThe X-Noirdoc-Provider header in the response names the provider.

Speech output

POST /v1/audio/speech
Family
tts
Shield
no
Streaming
no
Format
JSON, response as audio
Billing
characters in input

The body is JSON, as with the OpenAI Audio API. model is required and must be a model of the tts family from GET /v1/models.

input must be a non-empty text of at most 4,096 characters. voice must be a non-empty string. The provider determines which voices a model offers. The gateway answers violations with 400 invalid_tts_request.

The response contains the audio data as the provider delivers it, with the provider’s Content-Type.

Shell
curl https://api.noirdoc.de/v1/audio/speech \
  -H "Authorization: Bearer $NOIRDOC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "tts",
    "voice": "<voice>",
    "input": "Your appointment is on Tuesday at 10:00."
  }' \
  --output appointment.mp3
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.audio.speech.create(
    model="tts",
    voice="<voice>",
    input="Your appointment is on Tuesday at 10:00.",
)
response.write_to_file("appointment.mp3")
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 response = await client.audio.speech.create({
  model: "tts",
  voice: "<voice>",
  input: "Your appointment is on Tuesday at 10:00.",
});
const audio = Buffer.from(await response.arrayBuffer());
fs.writeFileSync("appointment.mp3", audio);

What Noirdoc changes

AreaBehaviour
ModelThe gateway resolves the model ID through the catalogue and uses it to select the provider.
StreamingNone. If stream is true or stream_format is set, the gateway answers with 400 streaming_not_supported_for_endpoint.
BillingThe gateway counts the characters in input and bills them.
ProviderThe X-Noirdoc-Provider header in the response names the provider.

Sub-routes

None. The gateway answers other paths under /v1/audio/ with 404 unsupported_endpoint.

Errors on these endpoints

Status Code Meaning
400 model_required The request names no model (model in the body, or in the form field for /v1/audio/transcriptions).
400 wrong_endpoint_for_model The model belongs to a different endpoint family or API format than the endpoint called.
400 streaming_not_supported_for_endpoint The request asks for streaming, but the endpoint does not support it.
400 invalid_request_body The body is not a JSON object or not encoded in UTF-8.
400 invalid_tts_request input or voice is missing or empty, or input is too long.
400 invalid_multipart_body The body is not valid multipart/form-data, or model, stream or response_format appears more than once.
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.
403 model_not_allowed_for_key The model is not one of this key's allowed models.
403 provider_not_allowed_for_tenant The organisation counts as bound by professional secrecy (§ 203 StGB); this excludes every provider that offers this model.
403 provider_not_allowed_for_key The key's restrictions (providers, data residency, CLOUD Act, § 203) exclude every provider of this model.
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 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.
404 model_not_available The model ID is not available to the organisation.
405 method_not_allowed The endpoint accepts only POST.
413 request_too_large The body exceeds the endpoint's size limit.
502 provider_unreachable The gateway could not connect to the provider, or the connection dropped.
504 provider_timeout The provider did not answer within the gateway's timeout. The response contains Retry-After with 10 seconds.

OpenAI reference

OpenAI’s API reference describes all other request and response fields: Audio (checked on 30 September 2026).