Last reviewed: 2026-07-31
Direct answer
A CometAPI audio transcription Node.js workflow needs three pieces: an OpenAI-compatible SDK client pointed at CometAPI, a readable audio stream, and response handling that matches the requested format. CometAPI documents /v1/audio/transcriptions for this job. Its default JSON response contains a text field, while alternative formats require different parsing.
Install the OpenAI package in an existing Node.js project:
npm install openai
Before running the script, use your deployment secret manager to expose COMETAPI_KEY to the Node.js process. Do not place its value in a source file, command example, URL, or log. Set COMETAPI_BASE_URL to the versioned base URL shown in the CometAPI SDK configuration guide
. The script reads both settings at runtime and passes the CometAPI value explicitly to the SDK’s apiKey option.
Save the following as transcribe.mjs:
import { createReadStream, statSync } from 'node:fs';
import { extname } from 'node:path';
import OpenAI from 'openai';
class OperatorError extends Error {
constructor(code) {
super(code);
this.name = 'OperatorError';
this.code = code;
}
}
const inputPath = process.argv[2];
const baseURL = process.env.COMETAPI_BASE_URL;
const k = process.env.COMETAPI_KEY;
const extension = extname(inputPath ?? '').slice(1).toLowerCase();
const model = process.env.COMETAPI_TRANSCRIPTION_MODEL || 'whisper-1';
const responseFormat = 'json';
const startedAt = Date.now();
const allowedExtensions = new Set([
'flac',
'mp3',
'mp4',
'mpeg',
'mpga',
'm4a',
'ogg',
'wav',
'webm',
]);
const logContext = {
event: 'audio_transcription',
model,
response_format: responseFormat,
file_extension: extension || null,
file_size_bytes: null,
};
let stage = 'validate_input';
try {
if (!inputPath) {
throw new OperatorError('INPUT_PATH_REQUIRED');
}
if (!baseURL || !k) {
throw new OperatorError('CLIENT_CONFIGURATION_MISSING');
}
if (!allowedExtensions.has(extension)) {
throw new OperatorError('UNSUPPORTED_EXTENSION');
}
const fileStats = statSync(inputPath);
logContext.file_size_bytes = fileStats.size;
if (!fileStats.isFile()) {
throw new OperatorError('INPUT_NOT_FILE');
}
if (fileStats.size === 0) {
throw new OperatorError('INPUT_EMPTY');
}
stage = 'configure_client';
const client = new OpenAI({ apiKey: k, baseURL });
const request = {
model,
file: createReadStream(inputPath),
response_format: responseFormat,
};
const language = process.env.AUDIO_LANGUAGE?.trim();
if (language) {
request.language = language;
}
stage = 'transcribe';
const transcription = await client.audio.transcriptions.create(request);
stage = 'validate_response';
if (typeof transcription.text !== 'string') {
throw new OperatorError('RESPONSE_TEXT_MISSING');
}
process.stderr.write(
JSON.stringify({
...logContext,
stage,
outcome: 'success',
duration_ms: Date.now() - startedAt,
transcript_characters: transcription.text.length,
}) + '\n',
);
process.stdout.write(transcription.text + '\n');
} catch (error) {
const httpStatus =
error && typeof error.status === 'number' ? error.status : null;
const fallbackCode =
stage === 'validate_input'
? 'LOCAL_INPUT_FAILED'
: stage === 'configure_client'
? 'CLIENT_CONFIGURATION_FAILED'
: 'TRANSCRIPTION_REQUEST_FAILED';
const errorCode =
error instanceof OperatorError ? error.code : fallbackCode;
process.stderr.write(
JSON.stringify({
...logContext,
stage,
outcome: 'error',
duration_ms: Date.now() - startedAt,
http_status: httpStatus,
error_code: errorCode,
error_name: error instanceof Error ? error.name : 'UnknownError',
}) + '\n',
);
process.exitCode = 1;
}
Run it against a short supported file after the runtime configuration is available:
node transcribe.mjs ./audio.mp3 > transcript.txt
On the happy path, transcript.txt receives only the transcript. The operational record goes to standard error and includes the stage, outcome, duration, model, response format, file extension, file size, and transcript character count. It does not contain the CometAPI value, full local path, audio bytes, transcript text, or raw upstream response.
Use this operator workflow for the first check:
- Choose a short recording whose words you already know.
- Run the command and confirm that it exits successfully.
- Compare
transcript.txtwith the known recording. - Check standard error for one structured success record.
- Run the script with a harmless unsupported extension to exercise the local error path.
- Confirm that the error record identifies the stage and fixed error code without revealing a path, transcript, or configured secret.
- Correct the input and rerun the happy path before connecting storage, queues, or user uploads.
This sequence separates API configuration problems from audio-quality and downstream application problems.
Who this is for
This tutorial is for Node.js developers who need searchable text from recorded meetings, voice notes, support recordings, captions, or other spoken media. It assumes you can run an ECMAScript module, install an npm package, and provide deployment configuration through the process environment.
It is intentionally scoped to source-language transcription. If the product requirement is English output from speech in another language, that is a different audio operation. The CometAPI transcription reference distinguishes transcription from its audio translation route.
Key takeaways
- The documented transcription operation requires a
fileandmodelin a multipart upload. - The OpenAI Node.js library accepts an
fs.ReadStream, socreateReadStream()can supply local audio. - The client must receive both the CometAPI value and versioned base URL explicitly, matching CometAPI’s SDK guide.
- JSON output should be checked for a string
textfield before downstream code accepts it. - Operational logs should describe the request without recording secrets, full paths, audio, transcripts, or unfiltered error bodies.
- Operators should validate one short file and one controlled failure before adding queues, storage, retries, or batch processing.
Sources checked
- Create transcription defines the route, multipart fields, supported formats, optional controls, response formats, and default JSON response shape.
- Use CometAPI with OpenAI SDKs
explains the Node.js package setup, explicit
apiKeyandbaseURLconfiguration, model selection, and common configuration failures. - OpenAI TypeScript and JavaScript API Library
documents accepted file-upload inputs and recommends
fs.createReadStream()when Node’s file-system API is available. - Node.js file-system documentation
documents
fs.createReadStream(), file statistics, read-stream behavior, and file-system errors used by the example.
Contract details to verify
Before treating the script as production-ready, verify each boundary against the current documentation and the environment where it will run.
Client configuration: The CometAPI SDK guide configures the Node.js client with a CometAPI-specific value and the versioned CometAPI base URL. The example reads COMETAPI_KEY into the short-lived local variable k and passes it explicitly as apiKey. This avoids relying on a different SDK default variable. If either runtime setting is absent, the script stops before opening the client.
Base URL and route: The SDK configuration must use CometAPI’s versioned base URL. The audio SDK method then targets the documented transcription path. A missing version segment or a client left on another provider’s default base URL changes where the request goes.
Upload fields: file and model are required. The endpoint accepts multipart form data, while the SDK receives a read stream and builds the upload request. Do not rename these fields in a wrapper without a contract test.
Accepted files: The documented formats are FLAC, MP3, MP4, MPEG, MPGA, M4A, OGG, WAV, and WebM. The example performs an extension preflight to catch an obvious mismatch early, but an extension alone does not prove that a file contains valid audio. Keep server-side rejection on the error path.
Model selection: The current reference shows whisper-1 as the default and example model. Availability can change independently of source code, so make the model configurable and verify it before deployment. The existing guide to checking the CometAPI model catalog
provides a broader preflight pattern.
Language and prompt: language is optional and uses an ISO-639-1 value. The documentation says supplying it can improve accuracy and latency. An optional prompt can guide style or continue a prior segment, and it should use the audio’s language. Start without a prompt unless the use case has a specific vocabulary or continuity requirement.
Response format: The documented options are json, text, srt, verbose_json, and vtt. This script requests json and therefore validates transcription.text. A subtitle or plain-text workflow must change both the request and the parser; changing only one creates a false failure or malformed downstream data.
Temperature: The documented range is zero through one, with zero as the default. Leave it at the documented default for the first integration unless there is a measured reason to expose it as an application setting.
Output boundary: The transcript is product data, not routine telemetry. Sending it to standard output lets the caller choose its destination. Sending only sanitized operational fields to standard error reduces the chance that transcript content enters general logs.
Failure modes
A useful operator workflow handles local validation, client configuration, the remote request, and response validation as separate stages.
Missing local path: Running the command without an argument produces INPUT_PATH_REQUIRED. Provide a specific local file and rerun. The log does not expose the path.
Unreadable or missing file: statSync() or the read stream can fail before a usable upload completes. The script reports LOCAL_INPUT_FAILED during input validation. Check the file’s existence and process permissions; do not interpret this as an API outage.
Empty input: A zero-byte file produces INPUT_EMPTY, preventing a pointless remote request. Confirm that the recording step finished and produced actual media.
Unsupported extension: An extension outside the documented set produces UNSUPPORTED_EXTENSION. Convert the file to a supported format or reject it at upload time. Do not merely rename an incompatible file.
Missing client configuration: If either required runtime setting is absent, the script emits CLIENT_CONFIGURATION_MISSING. Supply both through deployment configuration rather than editing the source file. For repository hygiene, follow Keep CometAPI Keys Out of Tutorial Repositories
.
Wrong base URL: The CometAPI SDK guide identifies an incorrect base URL, including a missing version segment, as a common reason the SDK calls the wrong destination or cannot find the expected route. Compare runtime configuration with the guide before changing request fields. The site’s base URL verification tutorial offers a focused checklist.
Rejected client identity: The SDK guide lists HTTP 401 as a client-configuration problem. The script records the status but not the response body or configured value. Correct the deployment setting and rerun a short test; repeatedly submitting an unchanged request will not diagnose it.
Invalid or unavailable model: A model identifier that is unavailable for the account or route can fail even when the upload is valid. Recheck the current model catalog, update COMETAPI_TRANSCRIPTION_MODEL, and repeat the known-file test.
Unexpected response shape: If the request is configured for JSON but the result lacks a string text field, the script emits RESPONSE_TEXT_MISSING. Preserve the sanitized log, verify response_format, and inspect the response only in a controlled debugging environment. Do not silently store undefined as a successful transcript.
Network or remote request failure: A connection failure may not have an HTTP status. The script records a null status and TRANSCRIPTION_REQUEST_FAILED. Use the stage, duration, and status together to distinguish a local preflight failure from a request that reached the remote operation. Keep retries outside this minimal script until the application can distinguish invalid input and configuration failures from transient transport failures.
Transcript quality does not match the known sample: A successful HTTP response is not proof that the text is suitable for the product. Compare the first result with a known recording. If the source language is known, test the documented language option. Preserve original audio according to the application’s privacy and retention rules, not in general-purpose logs.
The sanitized fields worth retaining are event, stage, outcome, duration_ms, model, response_format, file_extension, file_size_bytes, http_status, error_code, error_name, and transcript_characters. Exclude local paths, media bytes, transcript content, configured secrets, and raw remote bodies.
FAQ
Which audio files can I send?
The current CometAPI reference lists FLAC, MP3, MP4, MPEG, MPGA, M4A, OGG, WAV, and WebM. Validate both the extension and the actual media generated by your recording or conversion pipeline.
Why use createReadStream()?
The OpenAI Node.js library accepts an fs.ReadStream for file-upload parameters and recommends fs.createReadStream() in Node.js environments. The Node.js documentation defines the corresponding file-system API. This also matches CometAPI’s published JavaScript request shape.
Why does the example pass apiKey explicitly?
The CometAPI guide uses COMETAPI_KEY for its Node.js setup, while the generic SDK has its own defaults. Reading the CometAPI setting and passing it explicitly ensures that the client uses the intended value instead of depending on an unrelated default variable.
Should I always set language?
No. It is optional. When the source language is known, the CometAPI reference says an ISO-639-1 language value can improve accuracy and latency. Treat it as validated metadata rather than guessing from a filename.
Can this produce subtitles?
Yes. The endpoint documents srt and vtt response formats. Change the parser at the same time as the request. The JSON-specific transcription.text check in this example is not the correct contract for subtitle output.
Does transcription translate speech into English?
Not necessarily. This route transcribes in the source language. CometAPI documents a separate audio translation operation for English output. Choose the operation from the product requirement before writing storage or rendering code.
What should an operator log?
Useful fields include the operation name, stage, outcome, duration, selected model, response format, file extension, file size, HTTP status when available, a fixed error code, and transcript character count on success. Exclude configured secrets, full paths, media bytes, transcript text, and unfiltered upstream bodies.
Why send the transcript to standard output and logs to standard error?
That separation lets a caller redirect product output to a file or another process while retaining structured operational records independently. It also reduces the chance that transcript content is copied into routine logs.
Reader next step
Start with one short recording whose words you already know. Configure both client settings from the current CometAPI guide, run the script, confirm the text, and force one harmless error such as an unsupported extension. Verify that the error record is useful without revealing the file path or transcript.
After that check, decide whether the application needs source-language text, subtitles, or English translation, then set the response parser accordingly. Review the approved guidance for client-side timeout handling before placing the operation behind a web request or worker queue.
Start with CometAPI when you are ready to configure the service and run the known-file transcription check.