Stem Separation Callbacks
Webhook callback payload specification sent to your server when an audio stem separation or vocal removal task completes. Delivers isolated stem MP3 files including crystal-clear acapella and full-fidelity instrumental backing tracks.
When Callbacks Are Sent
The SongMesh API automatically triggers an HTTP POST request to your designated callBackUrl under these events:
- Stem Separation Complete (code: 200): Dispatched when the AI spectral separation engine finishes splitting the master audio into isolated stems (e.g. acapella and backing track).
- Multi-Track Stems Ready: If requested, individual instrument groups (bass, drums, guitars, strings) are delivered in origin_data array.
- Task Failure (code: 400/500): Dispatched if the input audio is corrupted, exceeds max duration limits, or contains unreadable codecs.
Webhook Payload Format
{
"code": 200,
"msg": "vocal Removal generated successfully.",
"data": {
"task_id": "3e63b4cc88d52611159371f6af5571e7",
"vocal_removal_info": {
"origin_url": "https://example.cn/music/master_song.mp3",
"vocal_url": "https://file.aiquickdraw.com/s/3d7021c9-fa8b-4eda-91d1-3b9297ddb172_Vocals.mp3",
"instrumental_url": "https://file.aiquickdraw.com/s/d92a13bf-c6f4-4ade-bb47-f69738435528_Instrumental.mp3",
"origin_data": [
{
"id": "efb902e8-ade5-467d-b7d0-61fa5e057d51",
"duration": 218,
"audio_url": "https://file.aiquickdraw.com/s/3d7021c9-fa8b-4eda-91d1-3b9297ddb172_Vocals.mp3",
"stem_type_group_name": "Vocals"
},
{
"id": "f239d1a9-0480-4ae5-ac28-feb7a12553cb",
"duration": 218,
"audio_url": "https://file.aiquickdraw.com/s/d92a13bf-c6f4-4ade-bb47-f69738435528_Instrumental.mp3",
"stem_type_group_name": "Instrumental"
}
]
}
}
}Callback Payload Fields
| Field | Type | Description |
|---|---|---|
code | integer | HTTP status code of the webhook delivery (200 = Success, 400/500 = Error). |
msg | string | Status message indicating the stem isolation outcome (e.g. "vocal Removal generated successfully."). |
data.task_id | string | Unique identifier of the stem separation task matching the taskId returned by POST /api/v1/createTask. |
data.vocal_removal_info | object | Container object holding URLs to all separated stem components. |
data.vocal_removal_info.vocal_url | string | Direct download URL for the isolated acapella vocal stem. |
data.vocal_removal_info.instrumental_url | string | Direct download URL for the isolated instrumental backing (karaoke) track. |
data.vocal_removal_info.origin_url | string | URL of the input master audio file that was submitted for stem extraction. |
data.vocal_removal_info.origin_data | array | Array containing detailed metadata for each separated stem track (including id, duration, audio_url, and stem_type_group_name). |
data.vocal_removal_info.origin_data[].stem_type_group_name | string | Classification of the stem (e.g. "Vocals", "Instrumental", "Backing_Vocals", "Bass", "Drums", "Guitar", etc.). |
Receiver Implementation Example
const express = require('express');
const app = express();
app.use(express.json({ limit: '10mb' }));
app.post('/suno-separate-vocals-callback', (req, res) => {
const { code, msg, data } = req.body;
const taskId = data?.task_id;
const removalInfo = data?.vocal_removal_info;
console.log('Received Suno Stem Separation callback:', {
taskId,
status: code,
message: msg
});
if (code === 200 && removalInfo) {
console.log('Stem isolation complete:');
console.log(`- Vocal Track: ${removalInfo.vocal_url}`);
console.log(`- Instrumental Track: ${removalInfo.instrumental_url}`);
// Process stem tracks
if (removalInfo.origin_data) {
removalInfo.origin_data.forEach(stem => {
console.log(`Stem [${stem.stem_type_group_name}]: ${stem.audio_url}`);
});
}
} else {
console.error('Stem separation failed:', msg);
}
// Always return HTTP 200 within 15 seconds to acknowledge receipt
return res.status(200).json({ status: 'received' });
});
app.listen(3000, () => {
console.log('Stem separation callback server running on port 3000');
});Webhook Security Recommendation
Always verify incoming webhook payloads on your server. Respond with a 200 OK immediately after parsing the payload to prevent redundant delivery retries from the webhook dispatcher.
Stem Extraction Modes: 2-Stem vs. Multi-Track Stems
Depending on your task parameters submitted to POST /api/v1/createTask (taskType: "separate_vocals"), the callback payload adapts to return two or twelve individual stems:
Splits the song into vocal_url (isolated dry & wet vocals) and instrumental_url (karaoke backing).
Populates origin_data with discrete tracks for Bass, Drums, Guitar, Piano/Keys, Strings, Brass, and FX for DAW remixing.
Webhook Delivery & Reliability Protocol
Webhook Receiver Examples
// app/api/webhook/suno-separate-vocals/route.ts
import { NextRequest, NextResponse } from 'next/server';
interface StemItem {
id: string;
duration: number;
audio_url: string;
stem_type_group_name: string;
}
interface VocalRemovalInfo {
origin_url?: string;
instrumental_url?: string;
vocal_url?: string;
backing_vocals_url?: string;
bass_url?: string;
brass_url?: string;
drums_url?: string;
fx_url?: string;
guitar_url?: string;
keyboard_url?: string;
percussion_url?: string;
strings_url?: string;
synth_url?: string;
woodwinds_url?: string;
origin_data?: StemItem[];
}
interface SeparateVocalsCallbackPayload {
code: number;
msg: string;
data: {
task_id: string;
vocal_removal_info: VocalRemovalInfo;
};
}
export async function POST(req: NextRequest) {
try {
const payload: SeparateVocalsCallbackPayload = await req.json();
const { code, msg, data } = payload;
const taskId = data?.task_id;
const removal = data?.vocal_removal_info;
console.log(`[Stem Separation Webhook] Task ${taskId} (Code: ${code})`);
if (code === 200 && removal) {
console.log('Stem extraction finished successfully:');
console.log(`- Acapella (Vocals): ${removal.vocal_url}`);
console.log(`- Instrumental (Karaoke): ${removal.instrumental_url}`);
// Log additional stems if multi-stem separation was requested
if (removal.origin_data && removal.origin_data.length > 2) {
console.log(`Multi-track stems extracted: ${removal.origin_data.length}`);
removal.origin_data.forEach((stem) => {
console.log(` * [${stem.stem_type_group_name}]: ${stem.audio_url} (${stem.duration}s)`);
});
}
} else {
console.error(`Stem separation failed: ${msg}`);
}
// Always acknowledge receipt immediately with HTTP 200
return NextResponse.json({ code: 200, msg: 'success' });
} catch (error) {
console.error('Webhook processing error:', error);
return NextResponse.json({ code: 500, msg: 'Internal server error' }, { status: 500 });
}
}{
"code": 200,
"msg": "success"
}Ready to integrate Stem Separation Callbacks?
Create your free account, obtain your Secret Key, and receive real-time isolated stems notifications with 5 free generation credits.