Generate Music Callbacks
Real-time asynchronous webhook notifications sent to your designated callBackUrl when dual-track music generation progresses and completes. Receive direct MP3 audio URLs, streaming audio links, high-res cover art, and duration metadata.
Usage Guide & Webhook Architecture
- Asynchronous Execution Model: Music synthesis takes 30–90 seconds. Supplying a
callBackUrlin your initialPOST /api/v1/createTaskrequest frees your client from holding open connections or polling. - Dual-Track Output Delivery: Suno AI generates 2 independent song arrangements per request. The final callback delivers both variation URLs in a unified JSON array.
- Multi-Stage Lifecycle Updates: Callbacks are dispatched at key production checkpoints: metadata and lyric planning (
text), first audio preview ready (first), and all tracks finalized (complete). - Zero Credit Surcharge: Webhook callback delivery is completely free of charge and does not consume any account credits.
Lifecycle Stages & Technical Constraints
Callback Stages (data.callbackType)
text: Prompt analysis and lyric structuring complete. Song title and style tags determined.first: First audio variation synthesis complete. Early streaming URL and preview audio available.complete: Final state. Both audio tracks are fully generated, mixed, mastered, and hosted on global CDNs.error: Task failed due to safety moderation filter, copyright flag, or upstream engine error.
HTTP Transport & Timeout Specification
- HTTP Method: Incoming requests are sent via
POSTwithContent-Type: application/json. - 15-Second Response Window: Your server must respond with HTTP
200within 15 seconds, otherwise the delivery is logged as a timeout. - Automatic Retry Policy: If your server returns non-200 or times out, the dispatcher retries up to 3 consecutive times with exponential backoff before terminating.
- Public Accessibility: The
callBackUrlmust be accessible via public HTTPS. Intranet or localhost addresses cannot receive webhooks.
Production Best Practices
- Immediate 200 Acknowledgment: Return HTTP 200 immediately upon receiving the JSON body, then offload heavy processing (e.g. downloading 100MB MP3s, transcribing, S3 uploading) to background queues.
- Idempotency Strategy: Use a compound key of
task_id + callbackTypeto deduplicate events and guard against duplicate delivery. - Handle Incomplete Variations: Always check
callbackType === 'complete'before flagging a generation job as ready for end users.
Troubleshooting & Verification Checklist
- Check server firewalls, WAF rules, and load balancers to ensure inbound POST requests on your callback route are permitted.
- For local development and testing, use reverse tunneling tools such as ngrok or Cloudflare Tunnel.
- Ensure your web application parses request bodies with
express.json()or equivalent middleware before reading parameters. - Inspect incoming request logs to verify that your service returns HTTP status 200 rather than 301/302 redirects.
Inbound HTTP Headers
| Header | Requirement | Description |
|---|---|---|
| Content-Type | required | application/json Inbound webhook payload encoded in UTF-8 JSON format |
| User-Agent | optional | Suno-Webhook-Dispatcher/1.0 Standard user agent identifier sent by the webhook worker |
When Callbacks Are Sent
The SongMesh API automatically triggers an HTTP POST request to your designated callBackUrl under these events:
- Text Planned (callbackType: 'text'): Triggered when the AI model finishes song title planning and lyrics verse formatting.
- First Track Ready (callbackType: 'first'): Dispatched as soon as the first audio variation is synthesized and available for streaming.
- All Tracks Complete (callbackType: 'complete'): Dispatched when dual-track generation finishes with high-quality MP3 downloads and album covers.
- Task Failure (callbackType: 'error'): Dispatched if the prompt violates content policy, audio synthesis fails, or model processing times out.
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/e231a481-9b11.mp3",
"stream_audio_url": "https://example.cn/stream/e231a481-9b11",
"image_url": "https://example.cn/images/e231a481-9b11.jpeg",
"prompt": "[Verse]\nNight city lights shining bright\nElectric guitar in the neon light\n[Chorus]\nRunning till the dawn breaks free",
"model_name": "chirp-v4-5",
"title": "Iron Man",
"tags": "electrifying, rock, energetic synth, powerful beat",
"createTime": 1786343609818,
"duration": 198.44,
"source_audio_url": "https://example.cn/source/source_sample.mp3",
"source_image_url": "https://example.cn/source/source_cover.jpeg",
"source_stream_audio_url": "https://example.cn/source/source_stream"
},
{
"id": "e231a482-9b11-4cb3-a9d2-5a218cadc7dd",
"audio_url": "https://example.cn/music/e231a482-9b11.mp3",
"stream_audio_url": "https://example.cn/stream/e231a482-9b11",
"image_url": "https://example.cn/images/e231a482-9b11.jpeg",
"prompt": "[Verse]\nNight city lights shining bright\nElectric guitar in the neon light\n[Chorus]\nRunning till the dawn breaks free",
"model_name": "chirp-v4-5",
"title": "Iron Man (Variation)",
"tags": "electrifying, rock, melodic guitar solo, high tempo",
"createTime": 1786343609818,
"duration": 204.12,
"source_audio_url": "https://example.cn/source/source_sample.mp3",
"source_image_url": "https://example.cn/source/source_cover.jpeg",
"source_stream_audio_url": "https://example.cn/source/source_stream"
}
]
}
}Callback Payload Fields
| Field | Type | Description |
|---|---|---|
code | integer | HTTP-style status code returned by the task processing engine. 200 indicates success; 400 or 500 indicates a failure. |
msg | string | Descriptive status message explaining the task outcome (e.g. "All generated successfully." or specific failure reason). |
data.callbackType | string | Lifecycle stage identifier: "text" (lyrics/title planned), "first" (track 1 ready), "complete" (all tracks ready), or "error" (failed). |
data.task_id | string | Unique task identifier, identical to the taskId returned when submitting the task to POST /api/v1/createTask. |
data.data | array | Array containing generated audio variations (typically 2 distinct track arrangements produced per request). |
data.data[].id | string | Unique UUID for the generated audio track variation. |
data.data[].audio_url | string | High-speed CDN direct download URL for the generated MP3 audio track. |
data.data[].stream_audio_url | string | Low-latency streaming audio URL (HLS / m3u8 format) for real-time web playback. |
data.data[].image_url | string | High-resolution album artwork cover image URL created for the track. |
data.data[].prompt | string | Lyrics, verse structure, or musical style prompt utilized during audio generation. |
data.data[].model_name | string | Underlying AI audio synthesis model used (e.g. "chirp-v4-5", "chirp-v4", "V6"). |
data.data[].title | string | Song title, either custom-specified or automatically generated by the lyrical model. |
data.data[].tags | string | Comma-separated musical genre, vibe, tempo, and instrumental tags. |
data.data[].createTime | integer | Unix millisecond timestamp when the audio track was synthesized. |
data.data[].duration | number | Total duration of the generated audio track in seconds (e.g. 198.44). |
data.data[].source_audio_url | string | Optional source audio URL if the generation was based on an uploaded audio file or extension. |
data.data[].source_image_url | string | Optional source cover image URL from the reference audio clip. |
data.data[].source_stream_audio_url | string | Optional source stream URL from the reference audio clip. |
Receiver Implementation Example
const express = require('express');
const app = express();
app.use(express.json({ limit: '10mb' }));
app.post('/webhook/suno', (req, res) => {
const { code, msg, data } = req.body;
console.log('Received Suno Webhook Callback:', {
status: code,
message: msg,
taskId: data?.task_id,
callbackType: data?.callbackType
});
if (code === 200 && data) {
const { callbackType, task_id, data: tracks } = data;
switch (callbackType) {
case 'text':
console.log(`[${task_id}] Lyrics & title planned:`, tracks);
break;
case 'first':
console.log(`[${task_id}] First audio variation ready:`, tracks?.[0]?.audio_url);
break;
case 'complete':
console.log(`[${task_id}] Both tracks generated successfully!`);
tracks?.forEach((track, index) => {
console.log(`Track #${index + 1}: ${track.title} (${track.duration}s)`);
console.log(`- MP3 URL: ${track.audio_url}`);
console.log(`- Stream URL: ${track.stream_audio_url}`);
console.log(`- Cover Art: ${track.image_url}`);
});
break;
case 'error':
console.error(`[${task_id}] Generation failed:`, msg);
break;
default:
console.log(`Unhandled callback stage: ${callbackType}`);
}
} 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: 'success' });
});
app.listen(3000, () => {
console.log('Suno 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.
// app/api/webhook/suno/route.ts
import { NextRequest, NextResponse } from 'next/server';
interface SunoTrackItem {
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 SunoCallbackPayload {
code: number;
msg: string;
data: {
callbackType: 'text' | 'first' | 'complete' | 'error';
task_id: string;
data?: SunoTrackItem[];
};
}
export async function POST(req: NextRequest) {
try {
const payload: SunoCallbackPayload = await req.json();
const { code, msg, data } = payload;
console.log(`[Webhook] Task ${data?.task_id} -> Stage: ${data?.callbackType} (Code: ${code})`);
if (code === 200 && data) {
if (data.callbackType === 'complete') {
// Both dual-track variations generated successfully
console.log(`[Complete] Total audio tracks: ${data.data?.length || 0}`);
for (const track of data.data || []) {
console.log(`Track: "${track.title}" (${track.duration}s)`);
console.log(`- MP3 URL: ${track.audio_url}`);
console.log(`- Stream URL: ${track.stream_audio_url}`);
console.log(`- Artwork: ${track.image_url}`);
// Persist to database or dispatch async download job
}
} else if (data.callbackType === 'first') {
// First track is ready for quick preview
console.log(`[First Track Ready] URL: ${data.data?.[0]?.audio_url}`);
} else if (data.callbackType === 'text') {
// Title and lyrics planning ready
console.log('[Text Ready] Lyrics and metadata planned');
}
} else {
console.error(`Task generation 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 Suno Music Generation Callbacks?
Create your free account, obtain your Secret Key, and receive real-time webhook updates with 5 free generation credits.