TypeScript SDK
transcodely is the official TypeScript / JavaScript SDK for the Transcodely API. It runs on Node.js 20+, ships with full type definitions for every request and response, and bundles a hand-rolled Connect-RPC transport so you don’t need to install Connect-ES separately. The SDK is alpha (0.1.0) — breaking changes are possible on minor bumps until 1.0.0.
Install
npm install transcodely
# or
pnpm add transcodely
# or
yarn add transcodelyThe SDK has one peer dependency, @bufbuild/protobuf ^1.10.0, used for generated message types. Most package managers will install it automatically.
Authenticate
The SDK takes the API key as an explicit constructor argument. The conventional environment variable is TRANSCODELY_API_KEY.
import { Transcodely } from "transcodely";
const client = new Transcodely({
apiKey: process.env.TRANSCODELY_API_KEY!,
});Test (ak_test_*) and live (ak_live_*) keys hit the same base URL — the environment is encoded in the prefix. Never embed an API key in browser code; the SDK is server-side only.
Create your first job
Resource methods live under lazy namespaces (client.jobs, client.videos, etc.). Method arguments are typed PartialMessage<T> shapes that auto-complete from the proto schema.
import {
Transcodely,
OutputFormat,
VideoCodec,
Resolution,
} from "transcodely";
const client = new Transcodely({ apiKey: process.env.TRANSCODELY_API_KEY! });
const job = await client.jobs.create({
inputUrl: "https://storage.example.com/source.mp4",
outputOriginId: "ori_x9y8z7w6v5",
outputs: [
{
type: OutputFormat.HLS,
video: [
{ codec: VideoCodec.H264, resolution: Resolution.RESOLUTION_1080P },
{ codec: VideoCodec.H264, resolution: Resolution.RESOLUTION_720P },
],
},
],
});
console.log(job.id, job.status);Method args use camelCase (inputUrl, outputOriginId); the SDK serializes them to snake_case (input_url, output_origin_id) on the wire automatically.
Watch a job to completion
client.jobs.watch(id) returns an AsyncIterable that emits one event per job-state change, auto-reconnecting on transient failures. Heartbeats are filtered by default. Pass an AbortSignal to cancel from your side:
import { JobStatus } from "transcodely";
const ac = new AbortController();
setTimeout(() => ac.abort(), 10 * 60 * 1000); // 10-minute ceiling
for await (const event of client.jobs.watch(job.id, { signal: ac.signal })) {
console.log(event.event, event.job?.status, event.job?.progress);
if (
event.job?.status === JobStatus.COMPLETED ||
event.job?.status === JobStatus.FAILED ||
event.job?.status === JobStatus.CANCELED
) {
break;
}
}The SDK retries the underlying server-side stream on APIConnectionError with exponential backoff and re-emits a SNAPSHOT event on every reconnect, so resuming is idempotent on the consumer side.
List with auto-pagination
Every list method returns a Page<T> that you can either await for a single page or .autoPage() over to walk every result.
// Single page
const page = await client.jobs.list({ pagination: { limit: 50 } });
console.log(page.items, page.nextCursor);
// All items, automatically across pages
for await (const job of client.jobs.list({ pagination: { limit: 50 } }).autoPage()) {
console.log(job.id, job.status);
}autoPage() stops when the API returns an empty next_cursor. See Pagination for the cursor model.
Handle typed errors
Every error inherits from TranscodelyError. Match concrete classes with instanceof:
import {
Transcodely,
TranscodelyError,
AuthenticationError,
NotFoundError,
RateLimitError,
InvalidRequestError,
} from "transcodely";
try {
await client.jobs.create({ inputUrl: "...", outputs: [] });
} catch (err) {
if (err instanceof InvalidRequestError) {
for (const v of err.errors) {
console.error(`${v.field}: ${v.description}`);
}
} else if (err instanceof RateLimitError) {
await new Promise((r) => setTimeout(r, err.retryAfterMs ?? 1000));
} else if (err instanceof NotFoundError) {
console.error("not found:", err.message);
} else if (err instanceof AuthenticationError) {
console.error("bad API key");
} else if (err instanceof TranscodelyError) {
console.error(`[${err.requestId}] ${err.code}: ${err.message}`);
} else {
throw err;
}
}Every error carries code, httpStatus, requestId, and raw (the original response body). See Errors for the full hierarchy.
Override idempotency
client.jobs.create automatically generates a UUID v4 Idempotency-Key so retrying within the same process is safe. For cross-process safety (queue workers, cron jobs), pass your own:
const job = await client.jobs.create({
inputUrl: "...",
outputOriginId: "ori_x9y8z7w6v5",
outputs: [/* ... */],
idempotencyKey: `transcode_asset_${assetId}_v1`,
});All other write methods also ship an Idempotency-Key automatically. See Idempotency for replay semantics and key-format guidance.
Request IDs
The most recent request ID is exposed for log correlation:
const job = await client.jobs.get("job_a1b2c3d4e5f6");
console.log(client.lastRequestId); // "req_..."Errors also carry err.requestId directly.
Configuration
Pass any of these to the constructor:
| Option | Default | Notes |
|---|---|---|
apiKey | — required — | Test or live API key |
baseUrl | https://api.transcodely.com | Override for staging or self-hosted |
timeoutMs | 30000 | Request timeout in milliseconds |
maxRetries | 3 | Retries on network errors, 5xx, 429, 503 with jittered backoff |
apiVersion | calendar version baked at SDK build time | Sent as Transcodely-Version |
defaultHeaders | — | Record<string, string> — sent on every request |
fetchImpl | globalThis.fetch | Inject a custom fetch (testing, browser shims) |
logger | — | (event: LogEvent) => void — structured request log hook |
const client = new Transcodely({
apiKey: process.env.TRANSCODELY_API_KEY!,
timeoutMs: 60_000,
maxRetries: 5,
defaultHeaders: { "X-Caller": "ingest-worker" },
logger: (event) => console.log(event.kind, event.requestId, event.durationMs),
});Where to go next
- API Reference — the full RPC surface, with request and response shapes.
- Webhook Integration — verify signed deliveries and handle events with
client.webhooks.constructEvent. - Errors — the typed error hierarchy in one place.
- Pagination — cursor model and auto-paging idioms.
- Idempotency — when and how to set your own key.
- SDK source on GitHub — full source, runnable examples in
examples/, and changelog.