@xconvert/sdk · TypeScript
Install
Shell
npm install @xconvert/sdkEnd-to-end: upload a file and convert it
This is the canonical flow. Every other example in this site is a slice of this:
TypeScript
import { Xconvert } from '@xconvert/sdk/v1';
import * as fs from 'node:fs/promises';
const xc = new Xconvert({ apiKey: process.env.XCONVERT_API_KEY! });
// 1. Read the file you want to convert.
const bytes = await fs.readFile('song.mp3');
// 2. Create an upload session.
const upload = await xc.uploads.createUpload({
requestBody: {
featureId: 'convert-mp3-to-aac',
files: [{ name: 'song.mp3', sizeBytes: bytes.length, contentType: 'audio/mpeg' }],
},
});
const handoff = upload.uploads[0];
// 3. PUT the bytes to the edge chunk endpoint.
// Small files: one chunk. Larger files: split + repeat with stepped Content-Range.
const putRes = await fetch(`${handoff.chunkEndpoint}?totalChunks=1`, {
method: 'PUT',
headers: {
'Content-Range': `bytes 0-${bytes.length - 1}/${bytes.length}`,
'Content-Type': 'application/octet-stream',
},
body: new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength),
});
if (!putRes.ok) throw new Error('upload chunk failed');
const done = await xc.uploads.completeUpload({ uploadId: upload.uploadId });
const fileId = done.files[0].fileId;
// 4. Submit the conversion. \`options: {}\` is fine — the server fills in
// baselines + defaults from the schema.
const job = await xc.submitJob({
featureId: 'convert-mp3-to-aac',
fileIds: [fileId],
fromType: 'mp3',
toType: 'aac',
processType: 'convert',
options: {},
});
// 5. Poll until terminal.
const final = await xc.pollUntilDone(job.id);
console.log(final.outputs?.[0]?.downloadUrl);Configuration
TypeScript
new Xconvert({
apiKey: 'xck_live_...', // required
baseUrl: 'https://api.staging.xconvert.com', // optional; default api.xconvert.com
headers: { 'X-Request-Id': '...' }, // optional
});What's on the client
Typed service handles for each API group, plus three shortcuts:
| Surface | Notes |
|---|---|
xc.jobs.* | createJob, getJob, listJobs, cancelJob |
xc.uploads.* | createUpload, completeUpload, cancelUpload |
xc.apiKeys.* | list/create/get/revoke/rotate |
xc.webhooks.* | list/create/patch/stop/resume + rotateSecret |
xc.features.* | validateFeatureOptions |
xc.me.* | getMe — current caller introspection |
xc.billing.* | overview, usage, history |
xc.submitJob(req, idempotencyKey?) | shortcut for jobs.createJob |
xc.getJob(id) | shortcut for jobs.getJob |
xc.pollUntilDone(id, {intervalMs, timeoutMs}) | polls jobs.getJob until terminal |
Common operations
List your jobs
TypeScript
const page = await xc.jobs.listJobs({ limit: 20, status: 'complete' });Cancel a queued job
TypeScript
await xc.jobs.cancelJob({ id: job.id });Caller introspection (auth + credit balance)
TypeScript
const me = await xc.me.getMe();
console.log(me.apiTier, me.credits.payg_remaining);Webhook endpoint
TypeScript
const endpoint = await xc.webhooks.createWebhookEndpoint({
requestBody: {
url: 'https://yoursite.com/hooks/xconvert',
events: ['job.completed', 'job.failed'],
},
});
console.log(endpoint.secret); // shown ONCE — sign incoming webhook payloads with itError handling
Service methods throw ApiError (re-exported from the generated client). The body follows RFC 9457 Problem Details:
TypeScript
import { ApiError } from '@xconvert/sdk/v1';
try {
await xc.submitJob({ ... });
} catch (e) {
if (e instanceof ApiError) {
console.log(e.status, e.body); // body.code, body.detail, body.extensions
} else { throw e; }
}Subpath versioning
TypeScript
import { Xconvert } from '@xconvert/sdk/v1'; // current
// import { Xconvert as XconvertV2 } from '@xconvert/sdk/v2'; // when it ships