API Documentation
Accuracy
Important considerations:
- This AI detector is very good at detecting pure AI songs (99.4%+ accuracy)
- However, as soon as 3rd party mastering or processing takes place, the detection becomes a lot trickier
- Any positive result should be examined closely before making any accusations
- This model was last updated in September, 2026 and may struggle to successfully detect AI audio generated with software released since then
Authentication
All API requests require authentication using an API key. Include your API key in the X-API-Key header of each request.
X-API-Key: sk_your_api_key_here
Endpoints
Submits an audio file for AI detection analysis. Returns results directly (typically takes 5-10 seconds).
Request Body
Provide one of audioUrl, spotifyTrackId, or isrc:
| Parameter | Type | Required | Description |
|---|---|---|---|
audioUrl | string | One required | URL of the audio file to analyze (MP3, WAV, M4A, MP4, or FLAC format) |
spotifyTrackId | string | One required | Spotify track ID (e.g., "2JUDGXTQYGQZrVVUgq40Ke"). The API will automatically extract the audio from Spotify. |
isrc | string | One required | ISRC code (e.g., "QT3F32442476"). The API will look up the matching track on Spotify and extract its audio. |
Full-length audio vs. previews
How much audio we analyze for spotifyTrackId and isrc lookups depends on your plan:
| Plan | Audio analyzed |
|---|---|
| Pro, Business | The full-length track, lossless where available |
| Verified (free) | The ~30 second preview clip from Spotify |
Every response tells you which one you got via audio_source. Preview analysis is still accurate, but a 30 second clip carries less signal than a full track, so scores can differ between the two — don't compare them directly.
Note that audio_source reports what we actually analyzed, not what your plan entitles you to. A handful of tracks have no full-length source we can reach; on a paid plan those fall back to the preview and come back as "preview" with anotice explaining why. Read the field rather than assuming from the plan.
Two things to know about previews. Spotify does not publish a preview for every track; when it's missing you'll get a No preview audio available error rather than a result. And previews are low-bitrate lossy MP3, so heavily compressed or processed material is harder to call than it is from lossless audio.
audioUrl is unaffected — whatever you point us at is what we analyze, on every plan.
Response
{
"result": {
"duration": 180.5,
"probability_ai_generated": 95.2,
"prediction": "Pure AI",
"confidence_score": 92.3,
"spectral_probabilities": {
"human": 4.8,
"processed_ai": 15.2,
"pure_ai": 80.0
},
"temporal_probabilities": {
"human": 2.1,
"processed_ai": 12.7,
"pure_ai": 85.2
},
"most_likely_ai_type": "Suno AI",
"treblo_probability": 99.99
},
"version": "v4.3",
"response_time": 8456,
"audio_source": "full",
"usage": {
"daily_remaining": 44,
"monthly_remaining": 849
}
}On a free plan the same spotifyTrackId request returns the analysis of the preview clip, flagged as such:
{
"result": { ... },
"version": "v4.3",
"response_time": 6120,
"audio_source": "preview",
"notice": "Analyzed a ~30 second Spotify preview clip, not the full track. Upgrade to Pro or Business to analyze full-length audio.",
"usage": {
"daily_remaining": 44,
"monthly_remaining": 849
}
}Stem analysis
When the whole-mix result is uncertain, we may also split the track into vocal and instrumental stems and score each one separately to reach a firmer answer. That helps most with a human vocal over an AI instrumental (or the reverse), which a whole-mix model can misread in either direction. When the split runs, the result carries a stem_verdict:
"stem_verdict": { "vocal": 75.1, "instrumental": 29.9 } // vocals and music
"stem_verdict": { "vocal": null, "instrumental": 52.5 } // instrumental track
"stem_verdict": { "vocal": 65.6, "instrumental": null } // a cappellaEach value is the probability (0-100) that the stem is AI-generated. A stem is null when the track has nothing there to judge: no singing for vocal, or no music beyond leftover residue for instrumental.
When both stems are present and one reads clearly more AI than the other, probability_ai_generated and prediction already account for it. A mid-range score can be raised, but never above 69, so stem evidence alone can't put a track in the high-confidence range. A score of 85 or above that reads as one AI stem over one human stem is lowered, since that points to a human-plus-AI collaboration rather than a fully generated track. You don't need to apply anything yourself. Tracks that aren't split don't carry the field.
Response Fields
| Field | Type | Description |
|---|---|---|
result | object | Analysis results from the AI detection service |
result.duration | number | Duration of the audio file in seconds |
result.probability_ai_generated | number | Probability (0-100) that the audio is AI-generated |
result.prediction | string | "Human Made", "Pure AI", or "Processed AI" based on analysis |
result.confidence_score | number | Confidence score (0-100) of the prediction |
result.spectral_probabilities | object | Breakdown of probabilities by spectral analysis (human, processed_ai, pure_ai) |
result.temporal_probabilities | object | Breakdown of probabilities by temporal analysis (human, processed_ai, pure_ai) |
result.most_likely_ai_type | string | Most likely AI generator type (field omitted when human-made, only present for AI-detected audio) |
result.treblo_probability | number | Probability (0-100) from Treblo's own AI detector that the track is Treblo-generated. Only present when Treblo's detector is confident (above 85) — when present, it drives prediction and confidence_score |
result.stem_verdict | object | Per-stem scores, present only when the track was sent for vocal/instrumental separation — see "Stem analysis" above. Omitted otherwise |
result.stem_verdict.vocal | number or null | Probability (0-100) that the isolated vocal stem is AI-generated. null when no singing was found |
result.stem_verdict.instrumental | number or null | Probability (0-100) that the isolated instrumental stem is AI-generated. null when there's no music to judge (a cappella) |
version | string | Version of the detection model that produced this result (e.g. "v4.3") |
response_time | number | Total response time for the API request in milliseconds |
audio_source | string | "full" if the full-length track was analyzed, "preview" if a ~30 second Spotify preview clip was (only present for spotifyTrackId and isrc lookups) |
notice | string | Explains a limitation applied to this result (only present when audio_source is "preview") |
usage | object | Current usage limits and remaining requests |
Code Examples
# Using audio URL
curl -X POST https://shlabs.music/api/v1/detect \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"audioUrl": "https://example.com/audio.mp3"}'
# Using Spotify track ID
curl -X POST https://shlabs.music/api/v1/detect \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"spotifyTrackId": "2JUDGXTQYGQZrVVUgq40Ke"}'
# Using ISRC
curl -X POST https://shlabs.music/api/v1/detect \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"isrc": "QT3F32442476"}'Error Codes
| Status Code | Description |
|---|---|
200 | Success - Audio analyzed successfully |
400 | Bad Request - Invalid request body or missing parameters |
401 | Unauthorized - Missing or invalid API key |
429 | Too Many Requests - Rate limit exceeded or too many concurrent requests |
500 | Internal Server Error - AI detection service temporarily unavailable |
503 | Service Unavailable - Spotify resolution service unreachable, or the request queue is saturated |
The distinction matters if you retry automatically. A 400 means the request or the audio is the problem and will return the same error however many times you send it — audio the detector cannot use (too short, too long, silent, corrupt, unsupported encoding) is a 400, and so is an unknown track or ISRC. Do not retry those.
A 500 or 503 means something on our side failed or was briefly unreachable. Those are worth retrying with exponential backoff. A 429 is also retryable, but only after the window it names has passed.
Error Response Format
Error responses vary based on the type of error:
Spotify Resolution Errors
{
"error": "Failed to extract audio from Spotify",
"details": "Unable to resolve Spotify track to downloadable audio. The track may not be available or the Spotify ID may be invalid.",
"spotifyTrackId": "4mUTfSM1IkqkGQ14k6iLV6",
"usage": {
"daily_remaining": 44,
"monthly_remaining": 849
}
}On a free plan, tracks Spotify publishes no preview for return this instead:
{
"error": "No preview audio available",
"details": "Spotify does not provide a preview clip for this track, and full-length audio requires a Pro or Business plan. Upgrade your plan, or pass a direct audioUrl instead.",
"spotifyTrackId": "4mUTfSM1IkqkGQ14k6iLV6",
"audio_source": "preview"
}Audio Processing Errors
{
"error": "Request timed out",
"details": "The audio file took too long to process. Please ensure your file is accessible and under 100MB.",
"audioUrl": "https://example.com/audio.mp3",
"suggestion": "Try with a different audio URL or check that your file is properly formatted and accessible.",
"usage": {
"daily_remaining": 44,
"monthly_remaining": 849
}
}Audio that fails for a reason inherent to the file is not re-analyzed if you send it again within the hour. The repeat is answered immediately from the earlier result and marked "cached": true. The error value is identical to the first response, so it stays safe to branch on; only details gains a note explaining that nothing was re-run:
{
"error": "Audio file is shorter than 10s.",
"details": "This is a property of the audio itself, so retrying the same file will return the same error. Submit different audio. This repeats a failure recorded within the last hour; the audio was not re-analyzed.",
"cached": true,
"spotifyTrackId": "4mUTfSM1IkqkGQ14k6iLV6",
"usage": {
"daily_remaining": 44,
"monthly_remaining": 849
}
}Transient failures — timeouts, service errors, download problems — are never cached, so a retry always gets a fresh attempt.
Error Response Fields
| Field | Type | Description |
|---|---|---|
error | string | Short error message describing what went wrong |
details | string | Detailed explanation and potential solutions (when available) |
spotifyTrackId | string | The Spotify track ID that failed (only present for Spotify-related errors) |
audioUrl | string | The audio URL that failed (only present for audio URL-related errors) |
isrc | string | The ISRC that failed to resolve (only present for ISRC-related errors) |
suggestion | string | Suggested actions to resolve the error (when available) |
cached | boolean | Present and true when this audio failed recently and was not re-analyzed |
usage | object | Remaining usage limits (included in most error responses) |
Rate Limits
Plans differ in request volume and in how much audio we analyze — Pro and Business analyze full-length tracks for Spotify and ISRC lookups, free plans analyze the ~30 second preview. See Full-length audio vs. previews above.
| Plan | Monthly Limit | Daily Limit | Per Minute |
|---|---|---|---|
| Verified | 10,000 requests | 500 requests | 10 requests |
| Pro | 100,000 requests | 5,000 requests | 15 requests |
| Business | 250,000 requests | 10,000 requests | 30 requests |