Skip to content

Suno API

RouteAPI provides a unified REST API for Suno AI music generation. Generate music from text, extend songs, clone voices, separate stems, and more.

Suno music generation is asynchronous. The typical flow:

  1. Submit a task to /suno/audios → receive a task_id
  2. Wait 2-3 seconds before starting to poll
  3. Poll every 3-5 seconds via /suno/tasks with action: "retrieve"
  4. When status becomes success → fetch the audio_url
StatusMeaningNext Step
submittedQueued for processingContinue polling
queuedWaiting in queueContinue polling
in_progressGeneratingContinue polling
success✅ CompleteRead audio_url from the first item in data
failure❌ FailedCheck error field
Terminal window
curl -X POST "https://api.routeapi.ai/suno/audios" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "chirp-v5-5",
"prompt": "A cheerful summer pop song with piano and guitar",
"async": true
}'

Response:

{ "success": true, "task_id": "task_xxxxx" }

Poll every 3-5 seconds until status becomes success:

Terminal window
curl -X POST "https://api.routeapi.ai/suno/tasks" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{ "action": "retrieve", "id": "task_xxxxx" }'
{
"id": "task_xxxxx",
"task_id": "task_xxxxx",
"status": "success",
"data": [
{
"id": "audio_1",
"audio_url": "https://cdn.suno.ai/xxx.mp3",
"video_url": "https://cdn.suno.ai/xxx.mp4",
"title": "Summer Breeze",
"duration": 183.5
}
]
}
Model IDMax DurationLyric LimitStyle LimitTitle Limit
chirp-v5-58 minutes5000 chars1000 chars100 chars
chirp-v58 minutes5000 chars1000 chars100 chars
chirp-v4-5-plus8 minutes5000 chars1000 chars100 chars
chirp-v4-54 minutes5000 chars1000 chars100 chars
chirp-v4150 seconds3000 chars200 chars80 chars
chirp-v3-5120 seconds3000 chars200 chars80 chars

The prompt field (non-custom mode) has a uniform 500 character limit across all models.

The core endpoint for audio operations: the action field selects the operation, and the request body carries the fields that action needs.

FieldTypeDefaultDescription
modelstringchirp-v4Generation model, recommend chirp-v5-5
actionstringgenerateOperation type (see below)
asyncboolean—Strongly recommended true to avoid timeouts. Only an explicit false selects the synchronous branch; when the field is omitted it is not forwarded, so the upstream default applies
ActionDescriptionRequired Fields
generateGenerate new music from promptprompt or custom=true + lyric + style
extendExtend existing audioaudio_id + continue_at
concatConcatenate audio clips into full trackaudio_id
coverRe-interpret existing song in new styleaudio_id
upload_coverCover uploaded audioaudio_id (via /suno/upload)
upload_extendExtend uploaded audioaudio_id + continue_at
artist_consistencySing with specified Personapersona_id + lyric / prompt
artist_consistency_voxVOX mode Persona singing (higher quality)persona_id + lyric / prompt
stemsSeparate into vocals + instrumentalaudio_id
all_stemsSeparate into all tracks (vocals, drums, bass, other)audio_id
replace_sectionReplace audio segmentaudio_id + replace_section_start + replace_section_end
underpaintingAdd AI instrumental to vocal trackaudio_id + underpainting_start + underpainting_end
overpaintingAdd AI vocals to instrumental trackaudio_id + overpainting_start + overpainting_end
samplesAdd AI samples in time rangeaudio_id + samples_start + samples_end
remasterRemaster audio to improve qualityaudio_id
mashupMerge multiple songsmashup_audio_ids (array)
inspoGenerate music inspired by 1-4 reference tracksaudio_urls (1-4 URLs)
FieldTypeDescription
promptstringNatural language description of music theme, mood, scene
lyricstringCustom lyrics with section markers like [Verse], [Chorus], [Bridge]
custombooleanEnable custom mode (allows specifying lyrics, title, style)
instrumentalbooleanGenerate instrumental music (no vocals)
titlestringSong title
stylestringStyle/genre/mood description, comma-separated
style_negativestringUnwanted styles (e.g., “heavy, rock, guitar”)
durationintegerDesired duration in seconds (10-360), hint only in custom mode
FieldTypeDescription
audio_idstringExisting audio ID (from generation or /suno/upload)
audio_urlsstring[]Reference audio public URLs (1-4)
mashup_audio_idsstring[]Source audio IDs for mashup
continue_atnumberExtend start time (seconds)
FieldTypeDescription
persona_idstringVoice persona ID (created via /suno/persona)
vocal_genderstringVocal gender preference: f (female) / m (male)
variation_categorystringRemaster precision: high / normal / subtle
Terminal window
curl -X POST "https://api.routeapi.ai/suno/audios" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "chirp-v5-5",
"prompt": "Uplifting electronic dance music with synth lead",
"async": true
}'
Terminal window
curl -X POST "https://api.routeapi.ai/suno/audios" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "chirp-v5-5",
"custom": true,
"title": "Summer Dreams",
"style": "pop, upbeat, piano",
"lyric": "[Verse]\nWalking on the beach at sunset\n[Chorus]\nSummer dreams never fade",
"async": true
}'
Terminal window
curl -X POST "https://api.routeapi.ai/suno/audios" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "chirp-v5",
"action": "extend",
"audio_id": "abc123-audio-id",
"continue_at": 30.5,
"async": true
}'
Terminal window
curl -X POST "https://api.routeapi.ai/suno/audios" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "stems",
"audio_id": "song-to-split",
"async": true
}'

Query task status and results. This is the main way to retrieve results from /suno/audios. POST /suno/fetch (batch) and GET /suno/fetch/{id} return the same records in a different envelope, and if you passed callback_url when submitting, RouteAPI also POSTs a completion payload (task_id, status, fail_reason, data) to that URL once the task reaches a terminal state.

Terminal window
curl -X POST "https://api.routeapi.ai/suno/tasks" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{ "action": "retrieve", "id": "task_xxxxx" }'

Response:

{
"id": "task_xxxxx",
"task_id": "task_xxxxx",
"status": "success",
"data": [
{
"id": "audio_1",
"audio_url": "https://cdn.suno.ai/xxx.mp3",
"video_url": "https://cdn.suno.ai/xxx.mp4",
"title": "Song Title",
"text": "Lyrics content",
"model_name": "chirp-v5-5",
"duration": 183.5
}
]
}

The task record’s data holds the upstream result. For song generation it is usually an array of clips; some operations (for example /suno/upload) return a single object instead, so read data as “an array or one object” rather than always indexing it. Terminal records also carry created_at, started_at, finished_at, elapsed, the sanitized response, and the submitted request.

Terminal window
curl -X POST "https://api.routeapi.ai/suno/tasks" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{ "action": "retrieve_batch", "ids": ["task_001", "task_002"] }'

Generate lyrics that can be used in /suno/audios’s lyric field.

FieldTypeRequiredDescription
promptstring✅Lyrics creation prompt
modelstringDefault default
Terminal window
curl -X POST "https://api.routeapi.ai/suno/lyrics" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{ "prompt": "Write upbeat summer pop lyrics with chorus" }'

Upload external audio file, returns audio_id for use in extend, cover, voice cloning operations.

Terminal window
curl -X POST "https://api.routeapi.ai/suno/upload" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{ "audio_url": "https://example.com/my-audio.mp3" }'

Manage voice personas (voice cloning).

Terminal window
curl -X GET "https://api.routeapi.ai/suno/persona" \
-H "Authorization: Bearer $ROUTEAPI_KEY"
Terminal window
curl -X POST "https://api.routeapi.ai/suno/persona" \
-H "Authorization: Bearer $ROUTEAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"audio_id": "uploaded-audio-id",
"name": "My Voice",
"vocal_start": 5.0,
"vocal_end": 15.0
}'
EndpointMethodDescription
/suno/voicesPOSTExtract vocal information from audio
/suno/stylePOSTGenerate style description from prompt
/suno/mashup-lyricsPOSTMerge two lyrics
/suno/wavPOSTExport WAV format (30-day validity)
/suno/mp4POSTExport MP4 video
/suno/midiPOSTExport MIDI file
/suno/timingPOSTGet lyrics timing for subtitles
/suno/voxPOSTExtract vocal segment (remove instrumental)

Errors after the request reaches the task handler use the task body:

{ "code": "invalid_request", "message": "prompt_empty (request id: ...)", "data": null }

Authentication and routing failures happen before that handler and keep the OpenAI-style body {"error": {"message": "...", "type": "...", "code": "..."}}. See Common errors.

StatusCodeCause
400invalid_requestA required field for the endpoint or action is missing; message names it (for example prompt_empty for /suno/lyrics, or audio_id_vocal_start_vocal_end_required for /suno/vox)
400task_not_existaction: "retrieve" with an id that is not one of your tasks
401—The API key is missing, invalid, or expired (OpenAI-style body)
403insufficient_user_quotaThe account balance or key quota cannot cover the pre-charge
429—The upstream channel reported a rate limit or saturation; RouteAPI replaces the provider’s raw message
502acedata_suno_request_failedThe upstream accepted the call but rejected it: content moderation, unknown audio_id, unsupported action. message carries the upstream explanation
502upstream_task_id_missingThe upstream returned a 2xx without a task ID, so the task could not be polled; the pre-charged amount is refunded
503get_channel_failedThe channel behind the task hit a hard fault, such as an unusable upstream account; RouteAPI replaces the provider’s raw message. (A model with no channel at all is rejected before the task handler with 503 model_not_found and the OpenAI-style body)
4xx / 5xxfail_to_fetch_taskThe upstream returned a non-2xx status; the status and body are forwarded, and the pre-charge is refunded

A failed task (polling returns failure) also refunds the pre-charged amount; its text is in the record’s error and message fields.

async function generateAndPoll(prompt) {
// Submit task
const res = await fetch('https://api.routeapi.ai/suno/audios', {
method: 'POST',
headers: { 'Authorization': 'Bearer $ROUTEAPI_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'chirp-v5-5', prompt, async: true })
});
const { task_id } = await res.json();
// Wait before first poll
await new Promise(r => setTimeout(r, 3000));
const deadline = Date.now() + 3 * 60 * 1000; // 3 min timeout
while (Date.now() < deadline) {
const poll = await fetch('https://api.routeapi.ai/suno/tasks', {
method: 'POST',
headers: { 'Authorization': 'Bearer $ROUTEAPI_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'retrieve', id: task_id })
});
const result = await poll.json();
if (result.status === 'success') return result.data;
if (result.status === 'failure') throw new Error(result.error || result.message);
await new Promise(r => setTimeout(r, 4000)); // Poll every 4s
}
throw new Error('Task timeout');
}

Q: Which model should I use?
Use chirp-v5-5 (latest and most capable). For stable older version, choose chirp-v4.

Q: How long does generation take?
generate usually 15-40 seconds. Processing operations like stems, all_stems, remaster may take 1-3 minutes.

Q: Can I use audio_url directly?
Yes, the CDN URL is ready for playback or download: curl -o song.mp3 "<audio_url>"

Q: How long is the track a single generate produces?
Usually 2-3 minutes of audio. Use extend to continue to 4-5+ minutes by setting continue_at.

Q: Common failure reasons?

message / codeCauseSolution
prompt_empty (invalid_request)/suno/lyrics or /suno/style without promptProvide the prompt
audio_id_required (invalid_request)/suno/wav, /suno/mp4, /suno/midi, or /suno/timing without audio_idPass the audio ID returned by a generation
acedata_suno_request_failed (502)The upstream rejected the submitted task, commonly content moderation or an unknown audio_idRead the upstream text in message, adjust the request, and retry
Polled status failureThe task failed after it was accepted; the reason is in the record’s error / messageAdjust the prompt and retry; the pre-charge was refunded
insufficient_user_quota (403)The account balance or key quota cannot cover the pre-chargeTop up the account or raise the key quota

Q: Concurrent request limits?
Yes, depends on account plan. Recommended concurrency ≤ 5, polling interval ≥ 3s.