Skip to content

StemSplit/node-stemsplit

Repository files navigation

@stemsplit/sdk

npm version Node versions License: MIT Downloads CI

Official Node.js / TypeScript SDK for the StemSplit stem-separation API. Typed client with automatic file uploads, job-completion polling, YouTube / SoundCloud jobs, voice denoising, and webhook signature verification. Zero runtime dependencies.

npm install @stemsplit/sdk
import { StemSplit } from '@stemsplit/sdk';

const client = new StemSplit();  // reads STEMSPLIT_API_KEY

// From a URL
const job = await client.jobs.create({
  sourceUrl: 'https://example.com/song.mp3',
  outputType: 'FOUR_STEMS',
});
const done = await job.waitForCompletion();
await done.downloadAll('./stems/');
// → stems/vocals.mp3  stems/drums.mp3  stems/bass.mp3  stems/other.mp3

// From a local file
const job2 = await client.jobs.create({ audio: './song.mp3', outputType: 'BOTH' });
const done2 = await job2.waitForCompletion();
await done2.downloadAll('./out/');
// → out/vocals.mp3  out/instrumental.mp3

Quick links

Features

  • StemSplit class with typed sub-resources for every public endpoint
  • Automatic file uploads — pass a file path, Buffer, Blob, or Uint8Array and the SDK handles the presigned-URL dance for you
  • job.waitForCompletion() — polls until done, returns the completed job; throws typed JobFailedError / JobExpiredError
  • job.downloadAll(dir) — downloads all stems to a directory in one call
  • jobs.iterAll() — async generator for paginated iteration over all jobs
  • YouTube and SoundCloud — separate stems directly from a URL, no download step required
  • Voice denoising — remove background noise from recordings via denoiseJobs
  • Webhook signature verification in two lines: webhooks.verifyAndParse(body, sig, secret)
  • Typed error hierarchy with documented codes — AuthenticationError, InsufficientCreditsError, RateLimitError, JobFailedError, and more
  • Automatic retries with exponential backoff + jitter on transient errors and 429 responses; honors Retry-After
  • Zero runtime dependencies — uses Node.js built-ins only (node:crypto, node:fs, node:stream)
  • Fully typed — ships .d.ts declarations; strict TypeScript clean

When to use this SDK vs alternatives

You want to … Use
Call the hosted StemSplit API from Node.js / TypeScript @stemsplit/sdk (this package)
Call the API from Python stemsplit-python
Use the API from Claude Desktop, Cursor, Cline, or Windsurf stemsplit-mcp
Wire StemSplit into n8n / Zapier / Make The no-code guides
Run inference locally without an API key demucs-onnx

Quick start

Install

npm install @stemsplit/sdk      # npm
yarn add @stemsplit/sdk         # yarn
pnpm add @stemsplit/sdk         # pnpm

Node.js 20+ required.

Authenticate

import { StemSplit } from '@stemsplit/sdk';

const client = new StemSplit({ apiKey: 'sk_live_...' });  // explicit
const client2 = new StemSplit();                           // reads STEMSPLIT_API_KEY

Get an API key at Settings → API Keys.

Separate stems from a local file

import { StemSplit } from '@stemsplit/sdk';

const client = new StemSplit();

const job = await client.jobs.create({
  audio: './song.mp3',            // path | Buffer | Uint8Array | Blob
  outputType: 'FOUR_STEMS',       // VOCALS | INSTRUMENTAL | BOTH | FOUR_STEMS | SIX_STEMS
  quality: 'BEST',                // FAST | BALANCED | BEST
  outputFormat: 'MP3',            // MP3 | WAV | FLAC
});

const done = await job.waitForCompletion();
const { files } = await done.downloadAll('./stems/');
console.log(files);
// { vocals: 'stems/vocals.mp3', drums: 'stems/drums.mp3', ... }

Separate from a public URL

const job = await client.jobs.create({
  sourceUrl: 'https://example.com/song.mp3',
  outputType: 'BOTH',
});
const done = await job.waitForCompletion();

YouTube separation

const job = await client.youtubeJobs.create(
  'https://youtube.com/watch?v=dQw4w9WgXcQ',
);
const done = await client.youtubeJobs.waitForCompletion(job.id);
console.log(done.videoTitle, done.outputs?.vocals?.url);

SoundCloud separation

const job = await client.soundcloudJobs.create(
  'https://soundcloud.com/artist/track',
);
const done = await client.soundcloudJobs.waitForCompletion(job.id);

Voice denoising

const job = await client.denoiseJobs.create({ audio: './interview.mp3' });
const done = await client.denoiseJobs.waitForCompletion(job.id);
const destPath = await client.denoiseJobs.downloadResult(done, './out/');
console.log('Denoised:', destPath);

List and iterate jobs

// One page
const { jobs } = await client.jobs.list({ status: 'COMPLETED', limit: 20 });

// All pages (async generator)
for await (const job of client.jobs.iterAll({ status: 'COMPLETED' })) {
  console.log(job.id, job.input.fileName);
}

Account balance

const balance = await client.account.get();
console.log(balance.balanceFormatted);  // "5 minutes"

Webhooks

Register a webhook in the dashboard, save the secret, then verify deliveries on your endpoint.

Express handler

import express from 'express';
import { webhooks } from '@stemsplit/sdk';

const app = express();
const SECRET = process.env.STEMSPLIT_WEBHOOK_SECRET!;

app.post('/stemsplit-webhook', express.raw({ type: '*/*' }), (req, res) => {
  try {
    const event = webhooks.verifyAndParse(
      req.body,
      req.headers['x-webhook-signature'] as string,
      SECRET,
    );

    if (event.event === 'job.completed') {
      console.log('Stems ready:', event.data.outputs);
    }

    res.sendStatus(200);
  } catch {
    res.sendStatus(401);
  }
});

Hono handler

import { Hono } from 'hono';
import { webhooks } from '@stemsplit/sdk';

const app = new Hono();

app.post('/stemsplit-webhook', async (c) => {
  const body = await c.req.arrayBuffer();
  const sig = c.req.header('x-webhook-signature') ?? '';

  const event = webhooks.verifyAndParse(
    Buffer.from(body),
    sig,
    process.env.STEMSPLIT_WEBHOOK_SECRET!,
  );

  console.log(event.event, event.jobId);
  return c.text('ok');
});

Error handling

Every non-2xx API response maps to a typed exception; the base class is StemSplitError.

import {
  StemSplit,
  AuthenticationError,
  InsufficientCreditsError,
  JobFailedError,
  RateLimitError,
} from '@stemsplit/sdk';

const client = new StemSplit();

try {
  const job = await client.jobs.create({ sourceUrl: 'https://example.com/song.mp3' });
  const done = await job.waitForCompletion();
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error('Check your STEMSPLIT_API_KEY:', err.message);
  } else if (err instanceof InsufficientCreditsError) {
    console.error(`Need ${err.requiredSeconds}s of credit. Buy more at ${err.purchaseUrl}`);
  } else if (err instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${err.retryAfter}s`);
  } else if (err instanceof JobFailedError) {
    console.error(`Job ${err.jobId} failed: ${err.errorMessage}`);
  }
}
Exception HTTP When
BadRequestError 400 Invalid parameters (FILE_TOO_LARGE, AUDIO_TOO_LONG, …)
AuthenticationError 401 Missing or invalid API key
InsufficientCreditsError 402 Not enough credits (exposes .requiredSeconds, .purchaseUrl)
PermissionDeniedError 403 API key revoked or expired
NotFoundError 404 Job not found
RateLimitError 429 Too many requests (exposes .retryAfter)
InternalServerError 5xx Server-side errors
JobFailedError Logical — thrown by waitForCompletion() when status is FAILED
JobExpiredError Logical — thrown by waitForCompletion() when status is EXPIRED
SignatureVerificationError Webhook signature mismatch
NetworkError Transport-level failure (DNS, timeout, …)

Configuration reference

new StemSplit({
  apiKey: 'sk_live_...',                    // string | undefined — env STEMSPLIT_API_KEY
  baseUrl: 'https://stemsplit.io/api/v1',   // override for testing / proxies
  timeout: 30_000,                          // ms — default 30s
  maxRetries: 3,                            // retries on transient errors — default 3
});

Limits and supported formats

  • Max file size: 100 MB
  • Max audio duration: 60 minutes
  • Rate limit: 60 req/min
  • Input formats: MP3, WAV, FLAC, M4A, AAC, OGG, WebM, WMA
  • Output formats: MP3, WAV, FLAC

Contributing

git clone https://github.com/StemSplit/node-stemsplit
cd node-stemsplit
npm install
npm run typecheck
npm run build
npm test

Issues, PRs, and questions are welcome at github.com/StemSplit/node-stemsplit.

License

MIT — see LICENSE.

About

Official Node.js / TypeScript SDK for the StemSplit API — stem separation, vocal removal, YouTube, webhooks

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors