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/sdkThe 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:
| Option | Meaning |
|---|---|
speakers | Request speaker labels. |
language | auto (default) or an ISO 639-1 language code. |
source | auto, captions or stt; applies to links. |
fresh | For links, skip reusing a transcription from the last 24 hours. |
filename | Required for Buffers, unnamed Blobs and streams. Can override a file's name. |
size | Required for streams and async iterables, in bytes. |
idempotencyKey | Defaults to a new UUID per call. |
onProgress | Receive progress events. |
signal | An 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 type | Fields |
|---|---|
upload | sent and total, in bytes. |
status | status: the job's current status. |
waiting_slot | retryAfter: seconds until the next attempt to get a job slot. |
reconnecting | No 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);
}
}| Field | Meaning |
|---|---|
message | Description of the error. |
code | API or job failure code, canceled, or a local SDK code. |
status | HTTP status, absent for job and local errors. |
details | Extra API error fields, such as minutes_needed or action_url; defaults to an empty object. |
retryable | Whether another attempt may help; defaults to false. |
transcriptionId | Job id when available. |
transcription | Last 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