Speko Docs
STT

Batch

Send a finished recording, get one transcript back. The OpenAI SDK works unchanged.

Use batch when you already have the whole file — a call recording, a voicemail, an uploaded clip. If audio is still arriving, you want streaming instead.

Call it

curl -X POST https://api.speko.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -F model=auto \
  -F file=@call.wav
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["SPEKO_API_KEY"],
    base_url="https://api.speko.ai/v1",
)

with open("call.wav", "rb") as audio:
    transcript = client.audio.transcriptions.create(model="auto", file=audio)

print(transcript.text)
import fs from 'node:fs';
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: 'https://api.speko.ai/v1',
});

const transcript = await client.audio.transcriptions.create({
  model: 'auto',
  file: fs.createReadStream('call.wav'),
});

console.log(transcript.text);

model: "auto" hands the choice to the router: it ranks the live board for your key's language and objective, then calls the winner. Pin a model instead by passing its id from GET /v1/models.

Two endpoints, one behaviour

EndpointBodyUse when
/v1/audio/transcriptionsmultipart/form-data with file and modelYou are using an OpenAI SDK.
/v1/transcribeRaw audio bytes, Content-Type: audio/wavYou have bytes in hand and do not want to build a multipart body.

Both route identically and return the same shape:

{ "text": "Your appointment is confirmed for Friday at nine." }
curl -X POST https://api.speko.ai/v1/transcribe \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -H "Content-Type: audio/wav" \
  -H "X-Speko-Language: es" \
  --data-binary @llamada.wav

Choosing the model

Routing headers work here exactly as they do everywhere else — see routing. The two that matter most for transcription:

X-Speko-Language: es
X-Speko-Objective: quality

Language picks which benchmark board ranks the candidates. It is the base subtag that counts: es-PR and es rank on the same Spanish board, because accent narrowing applies to TTS only.

Read x-route on the response to see which provider actually served it.

Batch and streaming rank separately

A provider's batch accuracy does not predict its streaming accuracy, and the board keeps them apart — wer for batch, werStream for the socket. Cartesia Ink-2 is the clearest case: its batch number is inflated by truncation, and the streaming path it normally runs on scores materially better.

So do not read a batch ranking and assume it holds for streaming. They are different measurements of different code paths.

Limits

  • Body size is capped by the router's replayable-body limit. A request over it gets 400; split long audio into chunks.
  • Failover is free here. Nothing has reached you yet, so a failed candidate is retried against the next one silently. x-speko-failover-count tells you how many were tried.
  • No word timings. The response is text. If you need timings, pin a provider and call it directly.

On this page