GlexirDocs
Dashboard

API

Audio

The Audio endpoints turn speech into text. audio.transcriptions transcribes audio in its own language. audio.translations (deprecated) transcribes and translates into English. Both are OpenAI-compatible and take a multipart file upload.

Glexir sells speech-to-text only. Text-to-speech and realtime voice are not available.

Transcribe a file

import { readFile } from "node:fs/promises";
import Glexir, { toFile } from "@glexir/sdk";

const glexir = new Glexir({ apiKey: process.env.GLEXIR_API_KEY });

const transcript = await glexir.audio.transcriptions.create({
  file: await toFile(await readFile("meeting.m4a"), "meeting.m4a"),
  model: "gpt-transcribe",
});

console.log(transcript.text);

Response:

JSON
{
  "text": "Thanks everyone for joining. Let's start with the roadmap.",
  "usage": { "type": "duration", "seconds": 42 }
}

Supported models

The TranscriptionModel type lists these IDs. It also accepts any other string.

ModelNotes
gpt-transcribeStart here. Supports languages and keywords.
gpt-4o-transcribeShuts down on 2027-02-26.
gpt-4o-mini-transcribeShuts down on 2027-02-26.
gpt-4o-mini-transcribe-2025-12-15Shuts down on 2027-02-26.
gpt-4o-transcribe-diarizeSpeaker labels. Shuts down on 2027-02-26.
whisper-1The only model for translations and verbose_json timestamps. Shuts down on 2027-02-26.

Only priced models work

A model must also be in Glexir's price book. Today the price book sells gpt-transcribe only, so the other models above return 403 with code model_not_priced. Call models.list() to see what your key can use right now.

File uploads

The request is multipart/form-data. The SDK builds it for you when you pass file.

  • The file must be 25 MB or smaller. Larger files return 413 with code file_too_large. Split long recordings into chunks.
  • Supported formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav and webm.
  • The format is detected from the filename, so the upload needs a name with the right extension.

file is an Uploadable: File | Blob | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array> | Response. Pass a File, or wrap other data with toFile(data, "name.ext"). If you pass a Blob or bytes without a name, the SDK names the part file.bin and the format can't be detected.

TypeScript
import Glexir, { toFile } from "@glexir/sdk";

const glexir = new Glexir();

// From a URL
const audio = await fetch("https://example.com/call.mp3");
const fromUrl = await glexir.audio.transcriptions.create({
  file: await toFile(audio, "call.mp3"),
  model: "gpt-transcribe",
});

// From a browser <input type="file">: a File already has a name
declare const picked: File;
const fromInput = await glexir.audio.transcriptions.create({ file: picked, model: "gpt-transcribe" });

toFile()

TypeScript
import type { Uploadable } from "@glexir/sdk";

// Exported from @glexir/sdk
declare function toFile(data: Uploadable | string, name?: string, options?: { type?: string }): Promise<File>;

Wraps data in a File with a filename and an optional MIME type. It throws a GlexirError if no filename is given and data is not already a File. A File passed with no name and no type is returned as-is.

The SDK sends text fields before the file part, writes arrays as repeated key[] parts, and objects as key[sub] parts. You don't need to do anything for this.

Response formats

response_format decides what the call returns. The SDK's return type follows it.

response_formatReturnsNotes
json (default)Transcription{ text, usage, ... }
verbose_jsonTranscriptionVerboseAdds duration, language, segments, words. whisper-1 only.
diarized_jsonTranscriptionDiarizedSpeaker-labelled segments. gpt-4o-transcribe-diarize only.
textstringPlain text.
srtstringSubRip subtitles.
vttstringWebVTT subtitles.
TypeScript
import Glexir, { toFile } from "@glexir/sdk";

const glexir = new Glexir();
const file = await toFile(await (await fetch("https://example.com/talk.mp3")).arrayBuffer(), "talk.mp3");

const text: string = await glexir.audio.transcriptions.create({
  file,
  model: "gpt-transcribe",
  response_format: "text",
});

Word and segment timestamps need whisper-1 with response_format: "verbose_json" and timestamp_granularities.

Languages and keywords

With gpt-transcribe, pass candidate languages and domain keywords to improve accuracy. Don't send language and languages together.

TypeScript
import Glexir, { toFile } from "@glexir/sdk";

const glexir = new Glexir();
declare const recording: Uint8Array;

const transcript = await glexir.audio.transcriptions.create({
  file: await toFile(recording, "support-call.wav"),
  model: "gpt-transcribe",
  languages: ["en", "yo"],
  keywords: ["Glexir", "Adebayo", "refund ticket"],
});

console.log(transcript.languages); // [{ code: "en" }], or [] when detection was unreliable

Stream a transcript

Set stream: true to get transcript events as they are produced. The call returns a Stream<TranscriptionStreamEvent>.

TypeScript
import Glexir, { toFile } from "@glexir/sdk";

const glexir = new Glexir();
declare const recording: Uint8Array;

const stream = await glexir.audio.transcriptions.create({
  file: await toFile(recording, "memo.webm"),
  model: "gpt-transcribe",
  stream: true,
});

for await (const event of stream) {
  if (event.type === "transcript.text.delta") process.stdout.write(event.delta);
  if (event.type === "transcript.text.done") console.log("\n", event.usage);
}

whisper-1 ignores stream and returns a normal response. See Streaming for Stream methods.

Event typeTypeFields
transcript.text.deltaTranscriptionTextDeltaEventdelta, logprobs?, segment_id? (diarization only)
transcript.text.segmentTranscriptionTextSegmentEventid, start, end, speaker, text. Diarize model with diarized_json.
transcript.text.doneTranscriptionTextDoneEventtext, languages?, logprobs?, usage?

Speaker diarization

gpt-4o-transcribe-diarize with response_format: "diarized_json" returns segments labelled by speaker. Name up to four speakers with known_speaker_names and matching known_speaker_references (data: URLs of 2 to 10 second samples). Unnamed speakers are labelled A, B and so on. For audio longer than 30 seconds, chunking_strategy is required.

This model is not in the price book today, so the call returns 403 model_not_priced. The types are documented below for completeness.

Translations (deprecated)

audio.translations.create() transcribes audio and translates it into English. It works with whisper-1 only, and OpenAI shuts down /audio/translations on 2027-02-26. whisper-1 is not in Glexir's price book today, so the call returns 403 model_not_priced. Use audio.transcriptions instead.

TypeScript
import type { APIPromise, RequestOptions, Translation, TranslationCreateParams, TranslationVerbose } from "@glexir/sdk";

// glexir.audio.translations (deprecated). Overloads narrow the result by response_format.
interface Translations {
  create(body: TranslationCreateParams & { response_format?: "json" }, options?: RequestOptions): APIPromise<Translation>;
  create(body: TranslationCreateParams & { response_format: "verbose_json" }, options?: RequestOptions): APIPromise<TranslationVerbose>;
  create(body: TranslationCreateParams & { response_format: "text" | "srt" | "vtt" }, options?: RequestOptions): APIPromise<string>;
}

response_format works as for transcriptions: json (default) returns Translation ({ text }), verbose_json returns TranslationVerbose (duration, language, text, segments?), and text, srt and vtt return a string.

TranslationCreateParams
fileUploadablerequired
The audio file, as for transcriptions.
model"whisper-1" | stringrequired
Only whisper-1.
promptstringoptional
Context for the model. Should be in English.
response_format"json" | "text" | "srt" | "verbose_json" | "vtt"optionaldefault "json"
Output format.
temperaturenumberoptional
Sampling temperature.

Per-second billing

Transcription is billed by audio duration, per second, at the model's per-minute rate divided by 60. Each request is billed at least 1 second, and partial seconds round up. See Pricing for the rate.

Glexir finds the duration in this order:

  1. usage.seconds when the response has duration usage (json, diarized_json, or the final transcript.text.done stream event).
  2. duration from a verbose_json response.
  3. Otherwise (text, srt, vtt, or no usage), the duration Glexir reads from the uploaded file. If the file can't be read, it estimates from the file size at about 16 kbit/s.

Before forwarding, Glexir reserves a hold sized from the file's duration (or the size estimate) and settles it when the response or stream ends. See Credits & billing.

Method reference

glexir.audio.transcriptions.create()

TypeScript
import type {
  APIPromise,
  RequestOptions,
  Stream,
  Transcription,
  TranscriptionCreateParamsBase,
  TranscriptionDiarized,
  TranscriptionStreamEvent,
  TranscriptionVerbose,
} from "@glexir/sdk";

type NonStreaming = { stream?: false | null };

// glexir.audio.transcriptions. Overloads narrow the result by response_format and stream.
interface Transcriptions {
  create(body: TranscriptionCreateParamsBase & NonStreaming & { response_format?: "json" }, options?: RequestOptions): APIPromise<Transcription>;
  create(body: TranscriptionCreateParamsBase & NonStreaming & { response_format: "verbose_json" }, options?: RequestOptions): APIPromise<TranscriptionVerbose>;
  create(body: TranscriptionCreateParamsBase & NonStreaming & { response_format: "diarized_json" }, options?: RequestOptions): APIPromise<TranscriptionDiarized>;
  create(body: TranscriptionCreateParamsBase & NonStreaming & { response_format: "text" | "srt" | "vtt" }, options?: RequestOptions): APIPromise<string>;
  create(body: TranscriptionCreateParamsBase & { stream: true }, options?: RequestOptions): APIPromise<Stream<TranscriptionStreamEvent>>;
}

POST /audio/transcriptions. The overloads above pick the return type from response_format and stream, as in the Response formats table. options are the per-request options described in Client configuration.

TranscriptionCreateParamsBase
fileUploadablerequired
Audio file, at most 25 MB: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav or webm. Needs a filename with an extension.
modelTranscriptionModelrequired
A speech-to-text model ID. A missing or non-transcription model returns 400 model_not_found.
response_formatAudioResponseFormatoptionaldefault "json"
json, text, srt, verbose_json, vtt or diarized_json.
languagestringoptional
ISO-639-1 code of the audio. With gpt-transcribe, use languages instead (not both).
languagesstring[]optional
Candidate languages (gpt-transcribe). ISO 639-1, some ISO 639-3, and zh-cn, zh-tw, zh-hk.
keywordsstring[]optional
Domain terms to bias recognition (gpt-transcribe). Entries must not contain <, >, CR or LF.
promptstringoptional
Context or a previous transcript, in the audio's language. Not supported by the diarize model.
temperaturenumberoptional
0 to 1. 0 lets the model pick automatically.
timestamp_granularitiesArray<"word" | "segment">optional
Needs response_format verbose_json (whisper-1 only).
includeArray<"logprobs">optional
logprobs works with json output on the gpt-4o-transcribe models.
chunking_strategy"auto" | VadConfigoptional
Required for the diarize model when audio is longer than 30 seconds.
known_speaker_namesstring[]optional
Up to 4 speaker labels for diarization, for example customer and agent.
known_speaker_referencesstring[]optional
data: URLs of 2 to 10 second samples, in the same order as known_speaker_names.
streamboolean | nulloptional
true returns a Stream of TranscriptionStreamEvent.

Other keys are sent as extra form fields.

VadConfig
type"server_vad"required
Voice activity detection.
prefix_padding_msnumberoptional
Audio to include before detected speech, in milliseconds.
silence_duration_msnumberoptional
Silence that ends a speech segment, in milliseconds.
thresholdnumberoptional
Detection sensitivity, 0.0 to 1.0.

Response types

Transcription (json)
textstringrequired
The transcript.
languagesArray<{ code: string }>optional
Detected languages (gpt-transcribe). Empty when detection was unreliable.
logprobsTranscriptionLogprob[]optional
With include: ["logprobs"]. Each has token?, bytes?, logprob?.
usageTranscriptionUsageoptional
TranscriptionDurationUsage { type: "duration"; seconds } or TranscriptionTokenUsage { type: "tokens"; input_tokens; output_tokens; total_tokens; input_token_details? }.
_request_idstring | nulloptional
SDK only. The x-request-id header.
TranscriptionVerbose (verbose_json)
durationnumberrequired
Audio length in seconds.
languagestringrequired
Detected language.
textstringrequired
The transcript.
segmentsTranscriptionSegment[]optional
id, seek, start, end, text, tokens, temperature, avg_logprob, compression_ratio, no_speech_prob.
wordsTranscriptionWord[]optional
word, start, end. With timestamp_granularities: ["word"].
usageTranscriptionDurationUsageoptional
Seconds billed.
TranscriptionDiarized (diarized_json)
task"transcribe"required
Always transcribe.
durationnumberrequired
Audio length in seconds.
textstringrequired
The full transcript.
segmentsTranscriptionDiarizedSegment[]required
id, type (transcript.text.segment), start, end, text, speaker. speaker is a known_speaker_names value, otherwise A, B and so on.
usageTranscriptionUsageoptional
Usage for the request.

Errors

StatusCodeWhen
400model_not_foundmodel is missing or is not a speech-to-text model.
400noneThe body is not multipart, or file is missing.
402credit_balance_exhausted, spend_limit_exceededThe hold can't be reserved.
403model_not_pricedThe model is not in the price book.
413file_too_largeThe file is over 25 MB.
429rate_limit_exceeded, concurrency_limit_exceededToo many requests per minute, or too many in flight.

See HTTP error codes for the full list.