DocsNode.js SDK

Node.js SDK

Use @transcript1/sdk to transcribe YouTube links and local files from server code. Download text or subtitles, track progress and handle errors.

Use @transcript1/sdk to create transcriptions, upload files and wait for results from TypeScript or JavaScript server code.

Install

npm i @transcript1/sdk

The examples use ES modules. Save them as .mjs files, or set "type": "module" in package.json for .js files. require() also works on Node 20.19+, for example require('@transcript1/sdk').

API key

Create a key on the API keys page. Set TRANSCRIPT1_API_KEY in your server's environment, or pass apiKey to the constructor:

import { Transcript1 } from '@transcript1/sdk';
 
const t1 = new Transcript1(); // reads TRANSCRIPT1_API_KEY
const other = new Transcript1({ apiKey: 't1_...' });

Without a key, the constructor throws Transcript1Error with code missing_api_key.

Transcribe

transcribe(input, options) creates a job and waits for its transcript. It returns a CompletedTranscription with status: 'completed' and a transcript field. Failed or canceled jobs reject.

const done = await t1.transcribe('https://youtu.be/dQw4w9WgXcQ');
console.log(done.transcript.text);
 
const file = await t1.transcribe('./interview.m4a', { speakers: true });

For a Buffer or Uint8Array, supply the filename so the SDK can identify the media type:

import { readFile } from 'node:fs/promises';
 
const buffer = await readFile('./call.mp3');
const call = await t1.transcribe(buffer, { filename: 'call.mp3' });

Strings starting with http:// or https:// are links; other strings are file paths. Only YouTube links and file uploads are supported for now. Files can be up to 2,000,000,000 bytes, with extensions mp3, wav, m4a, flac, ogg, opus, mp4, mov, webm or mkv.

You can also pass a Blob, a ReadableStream<Uint8Array> or an async iterable of Uint8Array chunks. A Blob needs filename unless it is a named File. Streams and async iterables need both filename and size in bytes.

Download

download(id, options) waits for completion and returns a string. JSON is the API's JSON text, not a parsed object.

const text = await t1.download(done.id); // text is the default
const withTimes = await t1.download(done.id, { timestamps: true });
const srt = await t1.download(done.id, { format: 'srt' });
const vtt = await t1.download(done.id, { format: 'vtt' });
const json = await t1.download(done.id, { format: 'json' });

timestamps: true works only with text; other formats reject with invalid_input. Failed or canceled jobs also make download reject.

Background jobs

Use transcriptions.create to submit work without waiting for the transcript. For a file, it finishes uploading before returning.

const job = await t1.transcriptions.create('./long-interview.mp4');
const now = await t1.transcriptions.get(job.id);
const finished = await t1.transcriptions.get(job.id, { wait: true });

Without wait, get returns the current state. With wait: true, it resolves when the job reaches completed, failed or canceled. Check finished.status before reading its transcript. Unlike transcribe, get does not reject because a job failed or was canceled.

List, delete and account

for await (const item of t1.transcriptions.list({ status: 'completed', limit: 50 })) {
  console.log(item.id, item.created_at);
}
 
await t1.transcriptions.delete(job.id);
const account = await t1.account();
console.log(account.minutes.remaining);

list fetches pages as you iterate. Filter by status or platform (youtube or upload). limit is the page size, from 1 to 100; the API defaults to 20. Returned objects keep the API's snake_case fields.

delete cancels a running job or deletes a finished job and its transcript. account returns your plan, minutes and limits.

Options

The constructor accepts apiKey, baseUrl, fetch and maxRetries. baseUrl defaults to TRANSCRIPT1_API_URL when set, otherwise https://api.transcript1.com. Pass fetch to use your own implementation. maxRetries defaults to 2 and accepts integers from 0 to 10.

transcribe and transcriptions.create share these options:

OptionMeaning
speakersRequest speaker labels.
languageauto (default) or an ISO 639-1 language code.
sourceauto, captions or stt; applies to links.
freshFor links, skip reusing a transcription from the last 24 hours.
filenameRequired for Buffers, unnamed Blobs and streams. Can override a file's name.
sizeRequired for streams and async iterables, in bytes.
idempotencyKeyDefaults to a new UUID per call.
onProgressReceive progress events.
signalAn AbortSignal to cancel the call.

transcriptions.get accepts wait, includeWords, onProgress and signal. Use includeWords: true for word timings; onProgress reports changes while waiting.

download accepts format, timestamps and signal. list also accepts signal. Pass { signal } as the options argument to transcriptions.delete(id, options) or account(options).

Progress

Pass onProgress to transcribe, transcriptions.create or a waiting transcriptions.get call:

await t1.transcribe('./interview.m4a', {
  onProgress(event) {
    console.log(event);
  },
});
Event typeFields
uploadsent and total, in bytes.
statusstatus: the job's current status.
waiting_slotretryAfter: seconds until the next attempt to get a job slot.
reconnectingNo extra fields; emitted once per connection outage while waiting.

Cancel a call

Pass an AbortSignal from an AbortController to cancel a call, or use AbortSignal.timeout to set a time limit:

await t1.transcribe('https://youtu.be/dQw4w9WgXcQ', {
  signal: AbortSignal.timeout(10 * 60_000),
});

An abort before the first request rejects with aborted and no job id. During an upload, the SDK tries to delete the job if it is still awaiting_upload, then rejects with aborted and the id.

Aborting a wait leaves the job running. The error's transcriptionId lets you resume with transcriptions.get(id, { wait: true }). To cancel the job itself, call transcriptions.delete(id).

While waiting for a job, the SDK retries network errors and HTTP 429, 500, 502, 503 and 504 responses without a retry limit. Reconnection waits increase from 2 to 4, 8, 16 and then 30 seconds. Other requests use maxRetries. Job creation waits and retries when all active-job slots are busy. Use signal to bound the total time.

Errors

Catch Transcript1Error to read API, job and SDK error codes:

import { Transcript1Error } from '@transcript1/sdk';
 
try {
  await t1.transcribe('./call.mp3');
} catch (error) {
  if (error instanceof Transcript1Error) {
    console.error(error.code, error.message, error.transcriptionId);
  }
}
FieldMeaning
messageDescription of the error.
codeAPI or job failure code, canceled, or a local SDK code.
statusHTTP status, absent for job and local errors.
detailsExtra API error fields, such as minutes_needed or action_url; defaults to an empty object.
retryableWhether another attempt may help; defaults to false.
transcriptionIdJob id when available.
transcriptionLast transcription object when available.

Local codes are missing_api_key, invalid_input, aborted, network_error and upload_token_refused. Non-JSON error responses use http_<status>.

A failed job without an error object produces transcription_failed. If a completed job has no transcript after fetching it, transcribe rejects with internal_error. See Errors for API codes and API reference for response fields.

Runtimes

Node 20.19+. Bun and Deno should work through their node: compatibility; the automated tests run on Node only. Use the SDK server-side only; never ship an API key to a browser.

Updated October 16, 2026