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.wavimport 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
| Endpoint | Body | Use when |
|---|---|---|
/v1/audio/transcriptions | multipart/form-data with file and model | You are using an OpenAI SDK. |
/v1/transcribe | Raw audio bytes, Content-Type: audio/wav | You 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.wavChoosing 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: qualityLanguage 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-counttells you how many were tried. - No word timings. The response is text. If you need timings, pin a provider and call it directly.