Song query and history API
This page covers three free query endpoints:
| Capability | Method | Endpoint |
|---|---|---|
| Query one song's generation status and result | POST | /api/music/query |
| Query the songs the current account has generated | GET | /api/music/songs |
| Query the parameters retained when a song was generated | GET | /api/music/songs/:song_id |
If you used accept-receipt mode (
accept_mode=async) on a generation endpoint, what you hold is a receipt number, not a song ID. Track progress withGET /api/music/requests/{request_id}and come back to the endpoints on this page once you have the realsong_id. See "Accept-receipt mode" in the Simple mode generation API.
Authentication and data scope
All three endpoints authenticate with the same API key:
Authorization: Bearer YOUR_API_KEY
Song history is isolated by the user_id the API key belongs to. Several API keys created under the same main account can read that account's song history, but cannot read another user's or another sub-site account's songs.
The history endpoints return only real generated songs. They exclude:
- generation placeholder records that start with
pending:; - source-audio uploads and enhanced-upload records;
- sub-results such as vocal/accompaniment separation and stems;
- songs belonging to other users or sub-site accounts.
1. Query generation status
Look up the current status and final result of one or more song IDs.
Endpoint: POST /api/music/query
Billing: Free.
Headers
| Parameter | Type | Required | Notes |
|---|---|---|---|
| Authorization | string | yes | Bearer YOUR_API_KEY |
| Content-Type | string | yes | application/json |
Body parameters
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
| model | string | no | suno-v6 |
Model version |
| song_ids | string | yes | - | Song IDs, separated by commas |
Request example
curl -X POST https://www.suno-api.io/api/music/query \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"song_ids": "clip_id_1,clip_id_2"
}'
Response example
[
{
"song_id": "clip_id_1",
"song_title": "Song title",
"status": "completed",
"audio_url": "https://example.com/audio.mp3",
"video_url": "https://example.com/video.mp4",
"cover_url": "https://example.com/cover.jpg",
"lyrics": "Lyrics text",
"style_tags": "Mandopop, acoustic",
"duration": 180.5,
"model_version": "suno-v6",
"created_at": "2026-05-21T10:00:00Z"
}
]
Compatibility notes
Older documentation may show song_ids as an array. The current recommendation is a comma-separated string, matching how the endpoint is actually called.
song_ids must hold real song IDs. A placeholder ID starting with pending: is not a final song_id and cannot be used here; querying only placeholder IDs may return an empty array [].
The model, model_version or platform model_name in a response may keep historical values. New tasks should use suno-v6, suno-v6-wild or suno-v6-mini; suno-v2 through suno-v5-5 are retired, and seeing those names in history does not mean the model can still be submitted.
While a generation task is pending, submitted or processing, audio_url, video_url and cover_url may be empty — that is normal for an unfinished task. Do not judge failure from an empty address alone; use status, and query again once the status is complete. Only when the status is complete and the addresses are still empty should you contact support with the song_id.
⚠️ Audio addresses live for 7 days — transfer your files in time
The
audio_url,video_url(and other media addresses such as WAV) returned here are served from the platform's object storage and expire after 7 days by default: the files are recycled and the old address then returns 404.
- Move the files into your own storage within those 7 days; do not treat the address as a long-lived link.
- An expired address does not require regenerating the song and is not charged again: call this endpoint (
POST /api/music/query) again to get a fresh valid address for that song.
2. Query account song history
List the songs the main account behind the current API key has generated. Useful for building your own song list, picker or history page.
Endpoint: GET /api/music/songs
Billing: Free.
Query parameters
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
| p | integer | no | 1 |
Page number, starting at 1 |
| page_size | integer | no | 20 |
Items per page, maximum 100 |
| q | string | no | - | Fuzzy search by title, or exact search by full song ID |
| status | string | no | - | Exact status filter, for example completed, playable |
Results are ordered by created_at and internal record ID descending, so paging order stays stable.
Recovering a submission that timed out: generation endpoints give no intermediate response before acceptance. If your client timed out or the connection dropped while submitting, that order may already be accepted and generating. Glance at this endpoint (newest first): accepted songs appear in the list normally. Only resubmit once you have confirmed it is really absent, so you do not pay twice. See "Wait times and timeout settings" in the New API overview.
Request example
curl "https://www.suno-api.io/api/music/songs?p=1&page_size=20&status=completed" \
-H "Authorization: Bearer YOUR_API_KEY"
Response example
{
"success": true,
"message": "",
"data": {
"page": 1,
"page_size": 20,
"total": 42,
"items": [
{
"song_id": "8e31b3c0-example-song-id",
"title": "City in the Night",
"status": "completed",
"generation_type": "custom_generate",
"model": "suno-v6",
"duration": 187.42,
"audio_url": "https://example.com/audio.mp3",
"image_url": "https://example.com/cover.jpg",
"created_at": 1784000000,
"completed_at": 1784000120
}
]
}
}
Response fields
| Field | Type | Notes |
|---|---|---|
| song_id | string | Real song ID, usable for the detail lookup |
| title | string | Current song title, which the user may have renamed |
| status | string | Current status |
| generation_type | string | Generation type |
| model | string | Generation model |
| duration | number | Audio duration in seconds |
| audio_url | string | Audio address, may be empty while unfinished |
| image_url | string | Cover address, may be empty |
| created_at | integer | Creation time, Unix timestamp in seconds |
| completed_at | integer | Completion time, Unix timestamp in seconds; may be absent while unfinished |
The list endpoint does not return prompts, billing fields, account information or raw responses. For prompts and generation parameters, call the song detail endpoint.
3. Query generation parameters
Look up the prompt, style, model and source song the platform retained when the song was generated.
Endpoint: GET /api/music/songs/:song_id
Billing: Free.
Only songs of the main account behind the current API key can be read. Songs of other users or sub-site accounts are uniformly treated as "song not found".
Path parameter
| Parameter | Type | Required | Notes |
|---|---|---|---|
| song_id | string | yes | Real song ID |
Request example
curl "https://www.suno-api.io/api/music/songs/8e31b3c0-example-song-id" \
-H "Authorization: Bearer YOUR_API_KEY"
Response example
{
"success": true,
"message": "",
"data": {
"song_id": "8e31b3c0-example-song-id",
"title": "City in the Night",
"status": "completed",
"generation_type": "custom_generate",
"model": "suno-v6",
"duration": 187.42,
"audio_url": "https://example.com/audio.mp3",
"image_url": "https://example.com/cover.jpg",
"video_url": "",
"wav_url": "",
"created_at": 1784000000,
"completed_at": 1784000120,
"client_request_id": "example-request-id",
"client_request_index": 0,
"parameters": {
"prompt": "rain-washed city streets, lyrics about meeting again",
"style_tags": "Mandopop, acoustic, warm vocal",
"title": "City in the Night",
"model": "suno-v6",
"generation_type": "custom_generate",
"source_song_id": "",
"source_audio_url": "",
"custom_mode": null,
"instrumental": null,
"negative_tags": null,
"vocal_gender": null,
"lyrics_mode": null,
"wait_audio": null,
"style_weight": null,
"weirdness_constraint": null
},
"parameter_retention": {
"core_parameters_available": true,
"extended_parameters_available": false,
"sources": [
"suno_tasks"
],
"unavailable_fields": [
"custom_mode",
"instrumental",
"negative_tags",
"vocal_gender",
"lyrics_mode",
"wait_audio",
"style_weight",
"weirdness_constraint"
]
}
}
}
The parameters fields
| Field | Type | Notes |
|---|---|---|
| prompt | string | Generation prompt or lyrics |
| style_tags | string | Style tags |
| title | string | Retained generation title; an ordinary historical task may keep only the current title |
| model | string | Generation model |
| generation_type | string | Generation type |
| source_song_id | string | Source song ID for cover, extend and similar tasks |
| source_audio_url | string | Source audio address |
| custom_mode | boolean/null | Whether custom mode was used; null when not retained |
| instrumental | boolean/null | Whether the song is instrumental; existing historical data usually does not retain this separately |
| negative_tags | string/null | Excluded styles |
| vocal_gender | string/null | Vocal gender setting |
| lyrics_mode | string/null | Lyrics mode; existing historical data usually does not retain it |
| wait_audio | boolean/null | Whether it waited for the full audio; existing historical data usually does not retain it |
| style_weight | number/null | Style weight |
| weirdness_constraint | number/null | Creativity / weirdness parameter |
The prompt_view field (view prompts, added 2026-09-28)
prompt_view is a normalized structure dedicated to "view prompts": it organises the data into fixed sections per
generation type, so the client no longer has to decide which field to display. It is a purely additive field — the old
fields (parameters, parameter_retention) keep their names and meanings, and clients that do not parse the new field
are entirely unaffected.
"prompt_view": {
"type": "custom_generate",
"type_label": "Custom mode",
"generation": {
"model": "suno-v6", "max_mode": false, "duration": 182.4,
"title": "Four in the Morning#701f37", "title_base": "Four in the Morning", "title_suffix": "701f37",
"created_at": 1790421721
},
"inputs": {
"user_text": "...", "user_text_kind": "lyrics",
"user_style": "guochao electronic, deep sub bass, retro synth",
"style_tags": "guochao electronic, deep sub bass, retro synth",
"style_source": "user", "lyrics": "...",
"negative_tags": "", "is_instrumental": false
},
"extended": {
"vocal_gender": "m", "style_weight": 0.5, "audio_weight": 0.85,
"weirdness_constraint": 0.5, "variety": 2, "lyrics_mode": "manual",
"custom_mode": true
},
"reference": { "voice_name": "sv_40_34", "source_song_id": "", "source_title": "" },
"retention": {
"recorded_since": "2026-09-28", "missing_reason": "",
"not_applicable_fields": ["audio_weight"]
}
}
| Field | Type | Notes |
|---|---|---|
type / type_label |
string | Raw generation type / display label (simple generation, custom mode, sound-effect mode, voice clone generation…) |
generation.model |
string | Model used |
generation.max_mode |
bool | Whether Max Mode was on |
generation.duration |
number | Audio duration in seconds |
generation.title |
string | Title exactly as stored (may include a suffix) |
generation.title_base |
string | Display title with the trailing #xxxxxx suffix removed |
generation.title_suffix |
string | The suffix itself (without #); empty when there is none |
inputs.user_text |
string | User input (description or lyrics, depending on the type) |
inputs.user_text_kind |
string | lyrics / description / cover_requirements |
inputs.user_style |
string | The style the user typed (custom mode, voice, sound effects) |
inputs.style_tags |
string | The style that actually applied |
inputs.style_source |
string | user = entered by the user; suno_derived = inferred by Suno from the description |
inputs.lyrics |
string | Lyrics body; empty when there are none, [Instrumental] for instrumental songs |
inputs.negative_tags |
string | Excluded styles |
inputs.is_instrumental |
bool | Whether the song is instrumental |
extended.* |
— | Extended parameters, see below; fields that were not retained do not appear |
reference.voice_name |
string | Voice name (voice types only; the internal persona id is not returned) |
reference.source_song_id / source_title |
string | Source song for cover, extend and similar tasks |
retention.recorded_since |
string | Date extended parameters started being retained (2026-09-28) |
retention.missing_reason |
string | Why there are no extended parameters; historical data gives not_recorded_before_20260928 |
retention.not_applicable_fields |
string[] | Parameters this generation type never needed (do not display them as "missing parameters") |
Fields that may appear under extended: vocal_gender, style_weight, audio_weight,
weirdness_constraint, variety, lyrics_mode, custom_mode, plus the sound-effect group
sound_type / sound_bpm / sound_key / sound_loop. Empty values are never returned.
Three display rules (follow them rather than inferring):
- Distinguish where the style came from: when
style_source=suno_derived, display it as "style (inferred by Suno from your description)" and never as "your style"; - Internal prompts never appear: voice-cover types return only the 【style requirements】/【cover requirements】 the user typed; the fixed scaffold we assemble for the model appears in no field at all (historical data is sanitised the same way);
- Do not guess missing parameters: if
extendeddoes not contain it, it was not recorded then — useretentionto explain why.
Parameter retention notes
parameter_retention exists to separate "an empty value was explicitly passed" from "the field was never stored historically":
core_parameters_available: whether the main song task record exists; normallytruefor a valid detail lookup;extended_parameters_available: whether a related extended music task record was found;sources: which data tables this response drew on;unavailable_fields: fields that cannot be reliably recovered from historical data; these returnnullinsideparameters.
Ordinary historical songs usually kept the prompt, style, current title, model, generation type and source song, but did not store all advanced parameters separately. The platform never guesses missing values from generation_type.
Some extended music tasks also stored the original prompt, style, title, model, plus custom_mode, negative_tags, vocal_gender, style_weight and weirdness_constraint. Even when an extended record exists, instrumental, lyrics_mode and wait_audio may still be unrecoverable.
Song titles can be renamed by the user afterwards. When an ordinary historical task kept no separate original title, parameters.title may be the current title; when an extended task record exists, the original generation title stored there is preferred.
Not found or no permission
Business errors use a uniform response envelope. When the song does not exist or does not belong to the current account:
{
"success": false,
"message": "song not found"
}
This business error currently returns HTTP 200, so judge the result by the success field. A missing, invalid, expired or disabled API key returns HTTP 401.
Security notes
The song history and detail endpoints never return:
- API keys or token IDs;
- quota, billing or refund fields;
- account information or raw responses;
- internal object-storage keys;
- administrator errors or internal resource errors.
Get an API key
Create an API key in the console after signing up. ¥0.6 per run returns 2 tracks, downloads are unlimited, and no phone number is required.
Get API key Back to overview