API REFERENCE
Analyze Songs
On this page
/api/songs/analyzeAnalyze music using a state-of-the-art Audio Language Model (Music Flamingo) that listens directly to the audio waveform.
Authentication
x-api-key in header
bearerAuth bearer
Request
curl --request POST \
--url 'https://api.recoupable.dev/api/songs/analyze' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"audio_url": "https://example.com/song.mp3"
}'Try it
Fill in the fields, send the request from your browser, and read the live response. The curl below updates as you type.
Kept in this browser tab only and cleared when it closes.
curl --request POST \
--url 'https://recoup-api.vercel.app/api/songs/analyze' \
--header 'Content-Type: application/json' \
--data '{
"audio_url": "https://example.com/song.mp3"
}'Request body required
Music analysis request
application/json
presetstring · enumName of a curated analysis preset. Use instead of prompt for structured, optimized output. The 'full_report' preset runs all 13 presets in parallel and returns a comprehensive report. See List Analyze Presets for the full list of available presets.
Values: "catalog_metadata", "mood_tags", "lyric_transcription", "mix_feedback", "song_description", "music_theory", "similar_artists", "sample_detection", "sync_brief_match", "audience_profile", "content_advisory", "playlist_pitch", "artist_development_notes", "full_report"
promptstringText prompt or question about the music
minLength: 1 · maxLength: 24000
audio_urlstringrequiredPublic URL to an audio file (MP3, WAV, or FLAC, up to 20 minutes). Required in every mode, including a custom prompt. Verified before the model is called: the URL must answer a HEAD request (or a ranged GET) with 2xx within 10 seconds and an audio/* or application/octet-stream content type, else the request returns 422 and nothing is charged.
format: uri
max_new_tokensintegerMaximum number of tokens to generate
Default: 512
minimum: 1 · maximum: 2048
temperaturenumberControls output creativity — higher values produce more varied responses
Default: 1
minimum: 0 · maximum: 2
top_pnumberNucleus sampling probability cutoff
Default: 1
minimum: 0 · maximum: 1
do_samplebooleanEnable sampling (set true when using temperature or top_p)
Default: false
Responses
200Music analysis completed successfully+
application/json
statusstring · enumRequest status
Values: "success"
presetstringPreset used for analysis, when applicable
responseanyModel output for single-preset or custom-prompt analysis. May be plain text or structured JSON depending on the preset.
reportobjectFull report payload returned only when using the full_report preset
elapsed_secondsnumberInference time in seconds
format: float
400Bad request — missing or invalid fields, including a missing audio_url (missing_fields: ["audio_url"]) or both preset and prompt in one request+
application/json
statusstring · enumError status
Values: "error"
missing_fieldsarray<string>Path to the first invalid or missing field when validation fails
Item properties for missing_fields
string
errorstringError message describing what went wrong
401Unauthorized — invalid or missing API key / Bearer token+
application/json
statusstring · enumError status
Values: "error"
missing_fieldsarray<string>Path to the first invalid or missing field when validation fails
Item properties for missing_fields
string
errorstringError message describing what went wrong
402Insufficient credits — the balance cannot cover the base price of this request ($0.05 per model call, $0.65 for full_report). The model is not called, nothing is charged, and no Stripe object is created. The body includes a static billingUrl.+
application/json
errorstring · enumrequiredValues: "insufficient_credits"
remaining_creditsintegerrequiredThe account's balance, in credits (micro-dollars: 1,000,000 = $1.00).
required_creditsintegerrequiredThe base price of this request, in credits: 50000 ($0.05) for a single preset or custom prompt, 650000 ($0.65) for full_report. The per-second inference charge is added after the model returns.
billingUrlstringrequiredStatic link to the Recoup app, where a human can save a card and buy credits. It is a constant, not a freshly minted Stripe Checkout Session, so a credit-gated endpoint that keeps returning 402 creates nothing. To buy credits programmatically, call POST /api/credits/sessions.
422Unverifiable audio. Before the model is called, audio_url is checked with a HEAD request (a ranged GET for hosts that reject HEAD). It must answer 2xx within 10 seconds with an audio/* or application/octet-stream content type. When it does not, the model is not called and nothing is charged.+
application/json
statusstring · enumrequiredValues: "error"
errorstring · enumrequiredaudio_url_unreachable: the URL did not answer 2xx within 10 seconds. audio_url_not_audio: it answered, but with a content type that is not audio/* or application/octet-stream.
Values: "audio_url_unreachable", "audio_url_not_audio"
messagestringrequiredWhat the check observed, for the caller's logs.
500Server error — upstream model unavailable or inference failed+
application/json
statusstring · enumError status
Values: "error"
missing_fieldsarray<string>Path to the first invalid or missing field when validation fails
Item properties for missing_fields
string
errorstringError message describing what went wrong
Full specification
Download the OpenAPI file for complete schemas, constraints, and examples.
Download releases.jsonView operation source
{
"description": "Analyze music using a state-of-the-art Audio Language Model ([Music Flamingo](https://www.universalmusic.com/universal-music-group-to-transform-music-experience-for-billions-of-fans-with-nvidia-ai/)) that listens directly to the audio waveform.",
"security": [
{
"apiKeyAuth": []
},
{
"bearerAuth": []
}
],
"requestBody": {
"description": "Music analysis request",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongAnalyzeRequest"
}
}
}
},
"responses": {
"200": {
"description": "Music analysis completed successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongAnalyzeResponse"
}
}
}
},
"400": {
"description": "Bad request — missing or invalid fields, including a missing `audio_url` (`missing_fields: [\"audio_url\"]`) or both `preset` and `prompt` in one request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongAnalyzeErrorResponse"
}
}
}
},
"401": {
"description": "Unauthorized — invalid or missing API key / Bearer token",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongAnalyzeErrorResponse"
}
}
}
},
"402": {
"description": "Insufficient credits — the balance cannot cover the base price of this request (`$0.05` per model call, `$0.65` for `full_report`). The model is not called, nothing is charged, and no Stripe object is created. The body includes a static `billingUrl`.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongAnalyzeInsufficientCreditsResponse"
}
}
}
},
"422": {
"description": "Unverifiable audio. Before the model is called, `audio_url` is checked with a `HEAD` request (a ranged `GET` for hosts that reject `HEAD`). It must answer 2xx within 10 seconds with an `audio/*` or `application/octet-stream` content type. When it does not, the model is not called and nothing is charged.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongAnalyzeAudioUrlErrorResponse"
}
}
}
},
"500": {
"description": "Server error — upstream model unavailable or inference failed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SongAnalyzeErrorResponse"
}
}
}
}
}
}