Audio transcription

Whisper-family speech-to-text via multipart upload, with verbose timestamps and SRT/VTT output.

POST /v1/audio/transcriptions is the multipart speech-to-text endpoint, modelled on OpenAI's Whisper API. The gateway routes to a Whisper-family model hosted on Scaleway or Tensorix.

At a glance

EndpointPOST /v1/audio/transcriptions (multipart)
Default modelsystran/faster-whisper-large-v3 (Tensorix Frankfurt)
Max file size25 MB per upload
Formats acceptedmp3, wav, m4a, webm, mp4, flac, ogg
Response formatsjson, text, srt, verbose_json, vtt

Node example

transcribe.ts
import { readFileSync } from 'node:fs';
import { createCleverRouter } from '@cleverrouter/sdk';

const cr = createCleverRouter({ apiKey: process.env.CLEVERROUTER_API_KEY! });

const res = await cr.transcribe(
  {
    name: 'meeting.mp3',
    type: 'audio/mpeg',
    data: readFileSync('./meeting.mp3'),
  },
  {
    model: 'systran/faster-whisper-large-v3',
    language: 'en',
  },
);

console.log((res as { text: string }).text);

Browser example

upload.ts
async function transcribeFile(file: File) {
  const res = await cr.transcribe(file, { language: 'de' });
  return (res as { text: string }).text;
}

Verbose JSON with timestamps

verbose_json adds segment- and word-level timestamps, plus the detected language and total duration:

verbose.ts
const res = await cr.transcribe(file, {
  response_format: 'verbose_json',
  timestamp_granularities: ['word', 'segment'],
});

const verbose = res as {
  text: string;
  language?: string;
  duration?: number;
  segments?: Array<{ id: number; start: number; end: number; text: string }>;
  words?: Array<{ word: string; start: number; end: number }>;
};

console.log(verbose.duration, verbose.segments?.length);

Response formats

response_formatReturnsBest for
json (default){ text: string }Plain transcripts
verbose_jsonExtended JSONSegments, words, language ID
textstringThe transcript only
srtstringSubtitle file for video
vttstringWebVTT subtitle format

Input types

type TranscribeInput =
  | File
  | Blob
  | { name: string; type?: string; data: ArrayBuffer | Uint8Array | Blob };

File and Blob are native browser/Bun types. The plain-object form is convenient when you read bytes from disk in Node — the SDK builds the multipart body for you.

Options

interface TranscribeOpts {
  model?: string;                // default: 'systran/faster-whisper-large-v3'
  language?: string;             // ISO-639-1 hint (e.g. 'en', 'de', 'fr')
  prompt?: string;               // bias transcription with vocab/context
  temperature?: number;
  response_format?: 'json' | 'text' | 'srt' | 'verbose_json' | 'vtt';
  timestamp_granularities?: Array<'word' | 'segment'>;
  provider?: 'scaleway' | 'tensorix';
}

cURL

curl https://api.cleverouter.eu/v1/audio/transcriptions \
  -H "Authorization: Bearer $CLEVERROUTER_API_KEY" \
  -F file=@meeting.mp3 \
  -F model=systran/faster-whisper-large-v3 \
  -F response_format=verbose_json

Provider notes

ModelProviderRegion
systran/faster-whisper-large-v3TensorixFrankfurt
openai/whisper-large-v3ScalewayParis

No Bedrock audio

Bedrock doesn't expose Whisper in eu-central-1. Audio routes through Scaleway or Tensorix only.

Common gotchas

  • Big files time out. Past ~10 minutes of audio, split the file yourself and merge transcripts. Whisper-large processes faster than realtime on Tensorix, but the upload + buffering on a long file often hits the SDK's 60s default timeout.
  • Use language if you know it. Auto-detection is good but forcing language: 'de' (or whatever) cuts hallucinations on short or noisy clips.
  • prompt is a vocab hint, not a system prompt. Paste names and jargon that should appear in the transcript verbatim.