Upload & Extend Audio Callbacks
Webhook callback payload specification sent to your server when an audio continuation task based on user-uploaded sound completes. Seamlessly links your uploaded voice note, instrumental motif, or audio demo with AI-generated verses, choruses, and full arrangements.
When Callbacks Are Sent
The SongMesh API automatically triggers an HTTP POST request to your designated callBackUrl under these events:
- Harmonic Extension Planning (callbackType: 'text'): Dispatched when continuation chord progressions, lyrical themes, and rhythm sections have been mapped from your uploaded sound clip.
- First Extended Track Ready (callbackType: 'first'): Dispatched when the first extended track variation continuing from the designated timestamp is synthesized and ready for streaming.
- All Extended Variations Complete (callbackType: 'complete'): Dispatched when both complete audio tracks (original clip + seamless extension) are finalized, mixed, and hosted.
- Task Failure (callbackType: 'error'): Dispatched if the uploaded audio cannot be decoded, continue_at timestamp is invalid, or moderation filters reject the prompt.
Webhook Payload Format
{
"code": 200,
"msg": "All generated successfully.",
"data": {
"callbackType": "complete",
"task_id": "2fac9a8109bf4a6385cf71e3b6999f72",
"data": [
{
"id": "e231a481-9b11-4cb3-a9d2-5a218cadc7dc",
"audio_url": "https://example.cn/music/uploaded_sample_extended_var1.mp3",
"stream_audio_url": "https://example.cn/stream/uploaded_sample_extended_var1",
"image_url": "https://example.cn/images/extended_artwork_1.jpeg",
"prompt": "[Chorus]\nCarrying the rhythm forward into the light\nUnfolding melodies through the starry night",
"model_name": "chirp-v4-5",
"title": "Acoustic Melody (Extended Chorus & Outro)",
"tags": "indie folk, warm acoustic guitar, cello harmony, gradual tempo build",
"createTime": 1786343609818,
"duration": 236.5,
"source_audio_url": "https://example.cn/uploads/user_guitar_riff_sample.mp3",
"source_image_url": "https://example.cn/images/default_audio_cover.jpeg",
"source_stream_audio_url": "https://example.cn/stream/user_guitar_riff_stream"
},
{
"id": "e231a482-9b11-4cb3-a9d2-5a218cadc7dd",
"audio_url": "https://example.cn/music/uploaded_sample_extended_var2.mp3",
"stream_audio_url": "https://example.cn/stream/uploaded_sample_extended_var2",
"image_url": "https://example.cn/images/extended_artwork_2.jpeg",
"prompt": "[Chorus]\nCarrying the rhythm forward into the light\nUnfolding melodies through the starry night",
"model_name": "chirp-v4-5",
"title": "Acoustic Melody (Extended Instrumental Climax)",
"tags": "indie folk, dramatic string crescendo, fingerpicked guitar solo",
"createTime": 1786343609818,
"duration": 248.8,
"source_audio_url": "https://example.cn/uploads/user_guitar_riff_sample.mp3",
"source_image_url": "https://example.cn/images/default_audio_cover.jpeg",
"source_stream_audio_url": "https://example.cn/stream/user_guitar_riff_stream"
}
]
}
}Callback Payload Fields
| Field | Type | Description |
|---|---|---|
code | integer | Status code of task processing. 200 indicates success; 400 or 500 indicates a failure. |
msg | string | Descriptive status message explaining the extension outcome (e.g. "All generated successfully."). |
data.callbackType | string | Lifecycle stage identifier: "text" (structural continuation planned), "first" (variation 1 ready), "complete" (all extended tracks ready), or "error" (failed). |
data.task_id | string | Unique task identifier, identical to the taskId returned when submitting the upload & extend request to POST /api/v1/createTask. |
data.data | array | Array containing generated audio variations that seamlessly extend your uploaded audio clip (typically 2 distinct arrangements). |
data.data[].id | string | Unique UUID for the extended audio variation record. |
data.data[].audio_url | string | High-quality master MP3 download URL combining the uploaded base sound seamlessly with the newly synthesized continuation. |
data.data[].stream_audio_url | string | Low-latency streaming audio URL for instantaneous in-browser or in-app preview playback. |
data.data[].image_url | string | High-resolution square cover artwork URL generated for this extended audio variation. |
data.data[].prompt | string | Continuation lyric verses or stylistic prompts appended to expand the musical theme. |
data.data[].model_name | string | AI generation engine used to synthesize and extend the music (e.g. "chirp-v4-5"). |
data.data[].title | string | Title assigned to the extended audio variation. |
data.data[].tags | string | Musical genre tags, instrumentation, vocal descriptors, and production aesthetics used in the extension. |
data.data[].createTime | integer | Unix millisecond timestamp recording when the extended variation was generated. |
data.data[].duration | number | Total duration of the final extended song (original audio + appended continuation) in seconds. |
data.data[].source_audio_url | string | URL of the original uploaded audio file that served as the seed and beginning of this extended song. |
data.data[].source_image_url | string | Cover artwork or placeholder image associated with the initial uploaded sound file. |
data.data[].source_stream_audio_url | string | Streaming URL of the initial uploaded sound recording. |
Receiver Implementation Example
const express = require('express');
const app = express();
app.use(express.json({ limit: '10mb' }));
app.post('/suno-upload-extend-callback', (req, res) => {
const { code, msg, data } = req.body;
console.log('Received Suno upload & extend callback:', {
taskId: data?.task_id,
callbackType: data?.callbackType,
status: code,
message: msg
});
if (code === 200 && data) {
const { callbackType, task_id, data: tracks } = data;
switch (callbackType) {
case 'text':
console.log(`[${task_id}] Uploaded sound analyzed, extension verses mapped:`, tracks);
break;
case 'first':
console.log(`[${task_id}] First extended variation ready:`, tracks?.[0]?.audio_url);
break;
case 'complete':
console.log(`[${task_id}] All extended variations rendered successfully!`);
tracks?.forEach((track, index) => {
console.log(`Extended Track #${index + 1}: ${track.title} (${track.duration}s)`);
console.log(`- Master MP3: ${track.audio_url}`);
console.log(`- Stream URL: ${track.stream_audio_url}`);
console.log(`- Uploaded Base Clip: ${track.source_audio_url}`);
});
break;
case 'error':
console.error(`[${task_id}] Extension failed:`, msg);
break;
}
} else {
console.error('Task failed or returned non-200 code:', code, msg);
}
// Always return HTTP 200 within 15 seconds to acknowledge receipt
return res.status(200).json({ status: 'received' });
});
app.listen(3000, () => {
console.log('Suno upload & extend webhook listener 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.
External Audio Extension & Seamless Concatenation
When submitting an extension job with an uploaded audio source to POST /api/v1/createTask (taskType: "upload_and_extend_audio"), the model analyzes the tail frequency spectrum at continue_at to ensure a natural acoustic bridge:
The continuation engine computes the pitch contour and harmonic cadence at the exact cut point, avoiding jarring key shifts or abrupt rhythm drops.
The resulting audio_url delivers the entire combined audio file from second 0 to the extended end, so client players do not need to stitch chunks client-side.
Webhook Delivery & Reliability Protocol
Webhook Receiver Examples
// app/api/webhook/suno-upload-extend/route.ts
import { NextRequest, NextResponse } from 'next/server';
interface UploadExtendedTrackItem {
id: string;
audio_url: string;
stream_audio_url: string;
image_url: string;
prompt: string;
model_name: string;
title: string;
tags: string;
createTime: number;
duration: number;
source_audio_url?: string;
source_image_url?: string;
source_stream_audio_url?: string;
}
interface UploadExtendCallbackPayload {
code: number;
msg: string;
data: {
callbackType: 'text' | 'first' | 'complete' | 'error';
task_id: string;
data?: UploadExtendedTrackItem[];
};
}
export async function POST(req: NextRequest) {
try {
const payload: UploadExtendCallbackPayload = await req.json();
const { code, msg, data } = payload;
console.log(`[Upload & Extend Webhook] Task ${data?.task_id} -> Stage: ${data?.callbackType} (Code: ${code})`);
if (code === 200 && data) {
if (data.callbackType === 'complete') {
console.log(`Uploaded audio continuation rendered! Variations: ${data.data?.length || 0}`);
for (const track of data.data || []) {
console.log(`Extended Track: "${track.title}" (Total Duration: ${track.duration}s)`);
console.log(`- Master MP3: ${track.audio_url}`);
console.log(`- Uploaded Base Clip: ${track.source_audio_url}`);
}
} else if (data.callbackType === 'first') {
console.log(`[First Extended Variation Ready] Stream URL: ${data.data?.[0]?.stream_audio_url}`);
} else if (data.callbackType === 'text') {
console.log('[Text Ready] Continuation lyrics and musical progression planned');
}
} else {
console.error(`Upload & Extend task failed: ${msg}`);
}
// Always acknowledge receipt immediately with HTTP 200
return NextResponse.json({ code: 200, msg: 'success' });
} catch (error) {
console.error('Webhook error:', error);
return NextResponse.json({ code: 500, msg: 'Internal server error' }, { status: 500 });
}
}{
"code": 200,
"msg": "success"
}Ready to integrate Upload & Extend Audio Callbacks?
Create your free account, obtain your Secret Key, and receive real-time audio extension notifications with 5 free generation credits.