# Node.js SDK

> @transcript1/sdk로 서버에서 영상 링크와 파일을 변환하세요. 텍스트·자막 다운로드, 진행 상황 확인, 오류 처리까지 예제로 살펴봐요.

Canonical: https://transcript1.com/ko/docs/sdk
Language: ko
Last updated: 2026-10-16

TypeScript나 JavaScript 서버에서 `@transcript1/sdk`로 변환 작업을 시작하세요. 파일 업로드부터 스크립트가 준비될 때까지 기다리는 과정까지 SDK가 처리해요.

YouTube 외 소셜 링크를 쓰려면 SDK 1.1.0 이상이 필요해요. SDK 1.0.1은 YouTube 링크만 지원하며 다른 링크는 서버에 보내기 전에 거부해요. `npm i @transcript1/sdk@latest`로 업데이트하세요.

1.1.0은 처음 지원한 여섯 플랫폼의 최소 버전이에요. Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat에는 해당 플랫폼 지원이 추가된 릴리스가 필요해요. 구버전에서는 링크를 서버에 보내기 전에 거부할 수 있어요.

## SDK 설치하기

```bash
npm i @transcript1/sdk
```

아래 예제는 ES 모듈 문법이에요. `.mjs`로 저장하세요. `.js`를 쓰려면 `package.json`에 `"type": "module"`을 지정하면 돼요. Node 20.19 이상에서는 `require('@transcript1/sdk')`와 같은 `require()` 호출도 지원해요.

## API 키 설정하기

대시보드의 [“API keys” 페이지](https://transcript1.com/dashboard/account/tokens)에서 키를 발급받으세요. 서버의 `TRANSCRIPT1_API_KEY` 환경 변수에 넣거나, 생성자 옵션인 `apiKey`로 전달할 수 있어요.

```javascript
import { Transcript1 } from '@transcript1/sdk';

const t1 = new Transcript1(); // reads TRANSCRIPT1_API_KEY
const other = new Transcript1({ apiKey: 't1_...' });
```

키를 설정하지 않으면 생성 시 `Transcript1Error`가 발생해요. 오류 코드는 `missing_api_key`예요.

## 스크립트가 완성될 때까지 기다리기

`transcribe(input, options)`를 호출하면 작업을 생성하고 완료될 때까지 기다려요. 성공하면 `status: 'completed'`인 `CompletedTranscription`을 반환하며, `transcript`에 스크립트가 들어 있어요. 작업이 실패하거나 취소되면 Promise가 reject돼요.

```javascript
const done = await t1.transcribe('https://youtu.be/dQw4w9WgXcQ');
console.log(done.transcript.text);

const file = await t1.transcribe('./interview.m4a', { speakers: true });
```

Buffer 또는 Uint8Array를 전달할 때는 파일 이름도 지정하세요. SDK가 이름으로 미디어 형식을 구분해요.

```javascript
import { readFile } from 'node:fs/promises';

const buffer = await readFile('./call.mp3');
const call = await t1.transcribe(buffer, { filename: 'call.mp3' });
```

문자열이 `http://`나 `https://`로 시작하면 링크로, 그 밖에는 파일 경로로 읽어요. YouTube, X, TikTok, Instagram, Facebook, Bluesky, Twitch, Dailymotion, Pinterest, LinkedIn, Snapchat의 링크와 파일 업로드를 지원해요. 지원하는 공개 녹화 영상과 자막 기능은 [지원 링크와 변환 옵션](https://transcript1.com/ko/docs/sources-and-options)에서 확인하세요. 추가 플랫폼의 링크는 HTTPS여야 해요.

파일 크기는 최대 2,000,000,000바이트예요. 지원 확장자는 mp3, wav, m4a, flac, ogg, opus, mp4, mov, webm, mkv예요.

소셜 게시물은 공개 상태여야 하며, 영상이 여러 개면 첫 번째 영상만 변환해요. 플랫폼은 API가 링크로 알아내요. 단축 링크의 지원 형식과 한도도 [지원 링크와 변환 옵션](https://transcript1.com/ko/docs/sources-and-options)에서 확인할 수 있어요.

Blob, `ReadableStream<Uint8Array>`, Uint8Array 청크를 내보내는 async iterable도 입력할 수 있어요. Blob에는 `filename`을 지정하세요. 이름을 가진 File이라면 생략해도 돼요. 스트림과 async iterable에는 `filename`과 바이트 단위 `size`를 모두 넣어야 해요.

## 텍스트와 자막 다운로드하기

`download(id, options)`로 원하는 형식의 스크립트를 받으세요. 작업 완료를 기다린 뒤 문자열로 반환해요. JSON 형식도 객체로 파싱하지 않고 API의 JSON 원문을 반환해요.

```javascript
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`는 `text` 형식 전용이에요. 다른 형식과 함께 지정하면 `invalid_input`으로 Promise가 reject돼요. 작업이 실패하거나 취소돼도 `download`의 Promise가 reject돼요.

## 작업만 시작하고 나중에 조회하기

변환 완료를 기다리지 않으려면 `transcriptions.create`로 작업을 시작하세요. 파일을 입력했다면 업로드까지는 마친 뒤 반환해요.

```javascript
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 });
```

`get`은 `wait`를 지정하지 않으면 현재 상태를 바로 반환해요. `wait: true`를 넣으면 `completed`, `failed`, `canceled` 중 하나로 끝날 때 Promise가 resolve돼요. 스크립트를 읽기 전에 `finished.status`를 확인하세요. `get`은 `transcribe`와 달리 작업 실패나 취소만으로 Promise를 reject하지 않아요.

## 작업 목록 조회, 삭제, 계정 확인

```javascript
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`는 순회할 때 필요한 페이지를 가져와요. `status` 또는 `platform`으로 범위를 좁힐 수 있어요. 플랫폼 값은 `youtube`, `x`, `tiktok`, `instagram`, `facebook`, `bluesky`, `twitch`, `dailymotion`, `pinterest`, `linkedin`, `snapchat`, `upload`예요. 페이지당 개수인 `limit`은 1~100이며 API 기본값은 20이에요.

응답 필드는 API의 `snake_case`를 그대로 사용해요. `media_id`의 내부 형식을 해석하지 말고 문자열 전체를 그대로 다루세요.

진행 중인 작업에 `delete`를 호출하면 취소해요. 이미 끝난 작업이라면 스크립트와 함께 삭제해요. `account`로는 요금제, 남은 분량, 사용 한도를 조회할 수 있어요.

## 생성자와 메서드 옵션

생성자 옵션은 `apiKey`, `baseUrl`, `fetch`, `maxRetries`예요. `baseUrl`을 생략하면 `TRANSCRIPT1_API_URL` 값을 사용하고, 이 환경 변수도 없으면 `https://api.transcript1.com`으로 연결해요. 별도의 fetch 구현이 필요하면 `fetch`로 전달하세요. `maxRetries`는 0~10 사이의 정수로 지정하며 기본값은 2예요.

`transcribe`와 `transcriptions.create`에서 공통으로 받는 옵션이에요.

| 옵션 | 용도 |
|---|---|
| `speakers` | 화자 분리 사용 여부 |
| `language` | 기본값은 `auto`예요. ISO 639-1 언어 코드로 직접 지정할 수도 있어요. |
| `source` | 링크는 `auto`나 `stt`를 사용해요. YouTube, X, TikTok, Bluesky, Dailymotion, LinkedIn에서 사용할 자막 트랙이 있으면 `captions`도 가능해요. |
| `fresh` | 같은 링크를 최근 24시간 안에 변환했어도 기존 스크립트를 재사용하지 않아요. |
| `filename` | Buffer, 이름 없는 Blob, 스트림에 필요한 파일 이름이에요. 기존 파일 이름을 바꾸어 보낼 때도 쓸 수 있어요. |
| `size` | 스트림과 async iterable에 필요한 파일 크기. 바이트 단위예요. |
| `idempotencyKey` | 생략하면 호출마다 새 UUID를 만들어요. |
| `onProgress` | 진행 상황을 받을 콜백 |
| `signal` | 호출 취소에 사용할 AbortSignal |

`transcriptions.get`에는 `wait`, `includeWords`, `onProgress`, `signal`을 넘길 수 있어요. 단어별 타임스탬프는 `includeWords: true`로 요청하세요. 대기 중 상태 변화는 `onProgress`로 받아요.

`download`의 옵션은 `format`, `timestamps`, `signal`이에요. `list`에도 `signal`을 넣을 수 있어요. `transcriptions.delete(id, options)`나 `account(options)`를 취소하려면 options 인자로 `{ signal }`을 전달하세요.

## 진행 상황 확인하기

`onProgress` 콜백으로 진행 상황을 받으세요. `transcribe`, `transcriptions.create`, 완료를 기다리는 `transcriptions.get`에서 사용할 수 있어요.

```javascript
await t1.transcribe('./interview.m4a', {
  onProgress(event) {
    console.log(event);
  },
});
```

| 이벤트 종류 | 전달되는 데이터 |
|---|---|
| `upload` | `sent`는 전송한 바이트 수, `total`은 전체 바이트 수예요. |
| `status` | `status`에 현재 작업 상태가 들어가요. |
| `waiting_slot` | `retryAfter`는 새 작업을 시작할 자리가 있는지 다시 확인하기까지의 대기 시간이에요. 초 단위예요. |
| `reconnecting` | 추가 필드는 없어요. 완료를 기다리다 연결이 끊기면 장애 한 번당 한 번 발생해요. |

## 호출 중단과 작업 취소

호출을 중단하려면 AbortController에서 만든 `AbortSignal`을 전달하세요. `AbortSignal.timeout`으로 제한 시간을 정할 수도 있어요.

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

첫 요청을 보내기 전에 중단하면 작업 ID 없이 Promise가 `aborted`로 reject돼요. 업로드 중이라면 작업이 아직 `awaiting_upload`일 때 SDK가 삭제를 시도해요. 이후 작업 ID를 포함한 `aborted` 오류로 Promise가 reject돼요.

대기만 중단한 경우에는 서버의 변환 작업이 계속 진행돼요. 오류에 있는 `transcriptionId`를 사용해 `transcriptions.get(id, { wait: true })`로 다시 기다릴 수 있어요. 서버 작업도 취소하려면 `transcriptions.delete(id)`를 호출하세요.

작업 완료를 기다릴 때는 네트워크 오류와 HTTP 429, 500, 502, 503, 504 응답을 횟수 제한 없이 재시도해요. 재연결 간격은 2, 4, 8, 16초 순으로 늘어나고 이후에는 30초예요. 다른 요청에는 `maxRetries`를 적용해요. 새 작업을 생성할 때 동시 작업 한도가 차 있으면 자리가 날 때까지 기다리며 재시도해요. 전체 대기 시간을 제한하려면 `signal`을 지정하세요.

## 오류 처리하기

API 호출, 변환 작업, SDK에서 발생한 오류는 `Transcript1Error`로 잡아 코드를 확인하세요.

```javascript
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);
  }
}
```

| 필드 | 확인할 내용 |
|---|---|
| `message` | 오류 원인을 설명하는 문구 |
| `code` | API·작업 오류 코드, `canceled`, 또는 SDK 내부 오류 코드 |
| `status` | HTTP 상태 코드. 작업 오류나 SDK 내부 오류에는 없어요. |
| `details` | `minutes_needed`, `action_url` 같은 API 오류의 추가 정보. 기본값은 빈 객체예요. |
| `retryable` | 재시도로 해결될 가능성이 있는지 알려 줘요. 기본값은 false예요. |
| `transcriptionId` | 작업 ID를 아는 경우에 포함해요. |
| `transcription` | 마지막으로 받은 작업 객체가 있으면 포함해요. |

SDK 내부 오류 코드는 `missing_api_key`, `invalid_input`, `aborted`, `network_error`, `upload_token_refused`예요. 서버의 오류 응답이 JSON이 아니면 `http_<status>`로 표시해요.

작업이 실패했는데 오류 객체가 없으면 `transcription_failed`를 사용해요. 완료된 작업을 조회한 뒤에도 스크립트가 없으면 `transcribe`의 Promise가 `internal_error`로 reject돼요. API 오류 코드는 [오류 처리](https://transcript1.com/ko/docs/errors), 응답 필드는 [API 레퍼런스](https://transcript1.com/ko/docs/api-reference)에서 확인하세요.

## 실행 환경

Node 20.19 이상에서 사용할 수 있어요. Bun과 Deno도 `node:` 호환 기능으로 동작할 것으로 예상하지만, 자동화 테스트는 Node에서만 진행해요. SDK는 반드시 서버에서 사용하고, API 키를 브라우저에 전달하지 마세요.
