Skip to content

Transcriptions

POST /v1/audio/transcriptions returns the transcript of an audio file, with optional timestamps.

Access: Keys with the media:generate scope, on an account with media access granted by Albastar Corp.

POST /v1/audio/transcriptions returns the transcript of an uploaded audio file. The request and response shapes are OpenAI's.

Parameters

A multipart/form-data body. A field outside the list fails with 400 bad-param.

NameTypeDescription
file requiredfileWAV, MP3, M4A, Ogg, WebM or FLAC audio, 20 MB at most
model requiredstringparakeet, or OpenAI's whisper-1, which runs as parakeet
languagestringauto (default) or one of Parakeet's 25 language codes, such as en or de; another value fails with 400 bad-param. Parakeet detects the spoken language itself and does not use the code
response_formatstringjson (default), text or verbose_json
timestamp_granularities[]stringWith verbose_json: segment (default), word, or both as two fields
promptstringAccepted and ignored
temperaturenumberAccepted and ignored
streamstringfalse only: the transcript arrives whole

Transcription models, each model's parameters and the 25 language codes: GET /v1/media/models?kind=transcription (Media jobs reference).

Headers

NameDescription
Idempotency-KeyRequest. A request of the same key with the same Idempotency-Key, fields and file returns the same job's transcript, or the same job's error. Without the header, an identical request of the same key in the same 10-minute window returns the first request's job, unless that job failed, expired or was cancelled: then the request runs as a new job. The windows start at :00, :10, :20, :30, :40 and :50 past the hour, UTC
X-Queue-TimeoutRequest. Seconds the job may wait in the queue, a whole number of 1 or more; a value above the kind's queue timeout is lowered to the queue timeout
X-Job-IdResponse. The media job mj_… that made the transcript
X-Trace-IdResponse, with X-Job-Id. The job's trace_id, 32 lowercase hex characters
Server-TimingResponse, with X-Job-Id. One entry <name>;dur=<ms>: whole milliseconds from the request's arrival to its job being queued
X-Queue-TimeoutResponse. The job's queue timeout in seconds
Retry-AfterResponse, on 503. 5
X-Should-RetryResponse, on 503 queued and 503 queue-timeout. false: OpenAI SDKs do not repeat the request

Request

The example downloads the reference clip of Narrator A, a synthetic voice, then transcribes the clip with word timestamps.

curl

curl -o reference.mp3 \
  https://api.albastov.com/v1/media/samples/reference-848c3d555461736a.mp3

curl https://api.albastov.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $ALBASTAR_API_KEY" \
  -F model=parakeet \
  -F [email protected] \
  -F response_format=verbose_json \
  -F "timestamp_granularities[]=word" \
  --dump-header -

Python

import os

import httpx
from openai import OpenAI

CLIP = (
    "https://api.albastov.com/v1/media/samples/"
    "reference-848c3d555461736a.mp3"
)

client = OpenAI(
    base_url="https://api.albastov.com/v1",
    api_key=os.environ["ALBASTAR_API_KEY"],
)

clip = httpx.get(CLIP)
clip.raise_for_status()
res = client.audio.transcriptions.with_raw_response.create(
    model="parakeet",
    file=("reference.mp3", clip.content),
    response_format="verbose_json",
    timestamp_granularities=["word"],
)
t = res.parse()
print(res.headers["x-job-id"], t.text, len(t.words))

JavaScript

const base = "https://api.albastov.com/v1";

const clip = await fetch(
  `${base}/media/samples/reference-848c3d555461736a.mp3`,
);
if (!clip.ok) throw new Error(`${clip.status} ${await clip.text()}`);

const form = new FormData();
form.append("model", "parakeet");
form.append("file", await clip.blob(), "reference.mp3");
form.append("response_format", "verbose_json");
form.append("timestamp_granularities[]", "word");
const res = await fetch(`${base}/audio/transcriptions`, {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.ALBASTAR_API_KEY}` },
  body: form,
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const t = await res.json();
console.log(res.headers.get("x-job-id"), t.text, t.words.length);

Response

200 with the transcript. The response Parakeet returned for the reference clip, with the header X-Job-Id: mj_qUCsYGCBLSxwrxRjJZUffq:

Response
{
  "duration": 13.975,
  "language": "auto",
  "task": "transcribe",
  "text": "Okay, so here's the plan. We land just after sunset, …",
  "words": [
    {"end": 0.72, "start": 0.16, "word": "Okay,"},
    {"end": 0.96, "start": 0.72, "word": "so"},
    {"end": 1.28, "start": 0.96, "word": "here's"},
    {"end": 1.6, "start": 1.28, "word": "the"},
    {"end": 2.08, "start": 1.6, "word": "plan."}
  ]
}

The response above is shortened: text holds the whole transcript, and words lists all 41 words. The whole text, wrapped at 76 characters:

Transcript
Okay, so here's the plan. We land just after sunset, grab the bags, and head
straight for the harbor. If the ferry's late again, and honestly, it usually
is, we'll get dinner by the water and wait it out. Sound good.
response_formatBody
json{"text": "..."} as application/json
textThe transcript and a newline, as text/plain
verbose_jsontask, language, duration in seconds, text; segments unless only word was asked for; words when word was asked for

language in verbose_json is the language the model reports, else the language sent: for the reference clip, sent without language, the value was auto. A segment has id, start, end and text, plus OpenAI's seek, tokens, temperature, avg_logprob, compression_ratio and no_speech_prob, which are always 0 or empty. A word has word, start and end in seconds.

The request waits for its job up to the job's queue timeout while the job is queued (60 s for transcription), and at most 85 s from arrival. An account holds 16 waiting requests at most; past that, the route answers 503 queued at once.

Errors

Errors use OpenAI's shape, {"error": {"message", "type", "param", "code"}}, plus job_id when a job exists. Branch on code.

StatusCodeMeaning
400bad-paramA field is missing, unknown or out of range; param names the field (file, model, language, response_format, timestamp_granularities, stream, X-Queue-Timeout)
400bad-uploadThe multipart body has no boundary or did not arrive whole
413too-largeThe file is over 20 MB
415multipart-onlyThe body is not multipart/form-data
415not-audioThe file is not WAV, MP3, M4A, Ogg, WebM or FLAC
429budget-exhaustedThe account's daily generation time is used up: That would go over today's generation time. It starts over at midnight UTC.; resets_at is the next 00:00 UTC
429too-many-openThe key has 1,000 jobs queued or running, the limit per key: You have 1000 jobs queued or running; that's the limit.
502The job's error codeThe job failed or was cancelled; job_id names the job
503queuedThe job is still queued: The job is still queued. It stays in /v1/media/jobs; poll GET /v1/media/jobs/<id>?wait=30 for it.; job_id names the job
503queue-timeoutThe job waited in the queue past its queue timeout and has expired.

Key, scope and rate-limit errors: Errors.