Skip to main content

White-Label API Integration

B2B

Build stem separation into your product

Who This Is For

You're building a product and want to add AI stem separation as a feature - without building the ML infrastructure yourself.

Music Apps
DAWs, editors
SaaS Platforms
Audio tools
Developer Tools
SDKs, plugins
Agencies
Client projects

Why Use StemSplit API?

No ML Infrastructure

Skip the $50k+ in GPU costs and months of ML engineering

Production Ready

Battle-tested with millions of audio files processed

Pay Per Use

No minimums. Scale from 100 to 1M files seamlessly

Webhooks & Async

Real-time notifications when jobs complete

Integration Architecture

Your User
Your Application
StemSplit API
Vocals
Drums
Bass
Other

Your users never see StemSplit - it's completely white-label

1

Set Up Webhooks

For production apps, use webhooks instead of polling. Get notified instantly when jobs complete.

Create webhook
curl -X POST https://stemsplit.io/api/v1/webhooks \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/stemsplit",
    "events": ["job.completed", "job.failed"]
  }'
Webhook payload (job.completed)
{
  "event": "job.completed",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "jobId": "job_abc123",
    "status": "COMPLETED",
    "outputs": {
      "vocals": { "url": "https://...", "size": 4521984 },
      "instrumental": { "url": "https://...", "size": 5832192 }
    }
  }
}
Security: Verify webhook signatures using the HMAC secret provided when creating the webhook.
2

Backend Integration

Here's a complete Node.js/Express example for handling the full flow:

server.js (Express example)
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');

const app = express();
app.use(express.json());

const STEMSPLIT_API_KEY = process.env.STEMSPLIT_API_KEY;
const WEBHOOK_SECRET = process.env.STEMSPLIT_WEBHOOK_SECRET;

// Store job -> user mapping (use your database in production)
const jobUserMap = new Map();

// 1. Your user requests stem separation
app.post('/api/separate', async (req, res) => {
  const { userId, audioUrl, outputType } = req.body;
  
  try {
    // Create job with StemSplit
    const response = await axios.post(
      'https://stemsplit.io/api/v1/jobs',
      {
        sourceUrl: audioUrl,
        outputType: outputType || 'ALL_STEMS',
        quality: 'BEST',
        outputFormat: 'MP3'
      },
      { headers: { 'Authorization': `Bearer ${STEMSPLIT_API_KEY}` }}
    );
    
    const jobId = response.data.id;
    
    // Map job to user for webhook handling
    jobUserMap.set(jobId, userId);
    
    // Return job ID to your frontend
    res.json({ 
      jobId,
      status: 'processing',
      message: 'Your audio is being processed'
    });
    
  } catch (error) {
    res.status(500).json({ error: 'Failed to start processing' });
  }
});

// 2. Handle webhooks from StemSplit
app.post('/webhooks/stemsplit', (req, res) => {
  // Verify webhook signature
  const signature = req.headers['x-webhook-signature'];
  const expectedSig = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest('hex');
  
  if (signature !== expectedSig) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const { event, data } = req.body;
  const userId = jobUserMap.get(data.jobId);
  
  if (event === 'job.completed') {
    // Notify your user (websocket, email, push notification, etc.)
    notifyUser(userId, {
      type: 'stem_separation_complete',
      outputs: data.outputs
    });
    
    // Clean up
    jobUserMap.delete(data.jobId);
  }
  
  if (event === 'job.failed') {
    notifyUser(userId, {
      type: 'stem_separation_failed',
      error: data.error
    });
    jobUserMap.delete(data.jobId);
  }
  
  res.json({ received: true });
});

// 3. Let users check job status
app.get('/api/jobs/:jobId', async (req, res) => {
  const { jobId } = req.params;
  
  const response = await axios.get(
    `https://stemsplit.io/api/v1/jobs/${jobId}`,
    { headers: { 'Authorization': `Bearer ${STEMSPLIT_API_KEY}` }}
  );
  
  res.json(response.data);
});

function notifyUser(userId, data) {
  // Implement your notification logic
  // WebSocket, email, push notification, etc.
  console.log(`Notifying user ${userId}:`, data);
}

app.listen(3000, () => console.log('Server running on port 3000'));
3

Handle Billing

Track usage and implement your own billing model:

Option 1: Pass-Through Pricing

Charge your users based on audio duration. Our API returns duration in seconds.

Your price = (duration_seconds × your_rate) + markup

Option 2: Subscription Tiers

Include stem separation as part of a subscription plan with usage limits.

  • Free: 5 minutes/month
  • Pro: 60 minutes/month
  • Enterprise: Unlimited

Option 3: Credits System

Sell credit packs. 1 credit = 1 second of audio processed.

Track usage per user
// After job completes, update user's usage
async function trackUsage(userId, jobData) {
  const durationSeconds = jobData.durationSeconds;
  
  await db.users.update({
    where: { id: userId },
    data: {
      stemMinutesUsed: { increment: durationSeconds / 60 },
      lastStemJob: new Date()
    }
  });
  
  // Check if user exceeded their plan limits
  const user = await db.users.findUnique({ where: { id: userId }});
  if (user.stemMinutesUsed > user.planLimit) {
    await notifyUserOverLimit(userId);
  }
}
4

Frontend UX Best Practices

Show Progress

Processing takes 30-90 seconds. Show a progress indicator with estimated time.

Preview Before Download

Let users preview stems in the browser before downloading.

Batch Processing

For power users, support uploading multiple files and processing them in parallel.

Error Handling

If processing fails, show a clear error message and offer to retry. Common errors: file too large, unsupported format.

📊 Volume Pricing

Building something big? Contact us for volume discounts:

Monthly VolumeUse CaseAction
< 100 hoursIndie apps, MVPsStandard pricing →
100-1,000 hoursGrowing SaaSContact for 20% off →
1,000+ hoursEnterprise, agenciesCustom pricing →

Building Something Cool?

We love seeing what developers build with our API. Reach out and tell us about your project - we might feature it, provide free credits for testing, or help with technical integration.

Contact Developer Relations