DS
DistroShield / API Docs
Start free trial

API Reference Β· v1

DistroShield API

REST API for pre-upload music quality control. Each /v1/analyze request runs four modules in parallel β€” AI detection, duplicate check, metadata validation, and recording fingerprint β€” returning a combined recommendation (pass / review / block) before your track reaches any DSP. Built for distributors' ingest pipelines.

Base URL
https://api.distroshield.com
Current model
distroshield-v7c

Model-specific attribution (live since 2026-05-04)

The API returns a classification_origin field that identifies the generator. When classification is ai, this field is one of suno_unlicensed, licensed_ai (Udio / ElevenLabs), or unknown_ai. When classification is human or hybrid, the field mirrors that value. Additive and backward-compatible.

Attribution is informational β€” the operational decision is yours. Common practice for indie distributors: distribute AI tracks to DSPs but withhold Content ID monetization claims until licensing clarity. Some DSPs demonetize AI streams automatically; Believe and TuneCore block proactively. Pick the policy that fits your DSP relationships and catalog mix.

Authentication

Every request (except GET /health) requires a Bearer API key issued by DistroShield. Keep your key secret β€” it's your client identity and billing binding.

Authorization: Bearer ds_YOUR_API_KEY_HERE

Keys are provisioned manually during onboarding. Missing or invalid key β†’ 401 unauthorized.

Quickstart

Minimal call that analyzes a track and returns classification. Replace YOUR_API_KEY and AUDIO_URL.

curl -X POST https://api.distroshield.com/v1/analyze \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "AUDIO_URL",
    "metadata": { "title": "Song A", "artist": "Artist A" },
    "client_track_id": "internal-123"
  }'

Typical latency: 3–6 seconds (audio download + inference). For high throughput, use POST /v1/batch.

POST /v1/analyze

Analyze a track

Synchronously analyze one audio URL. Returns classification, AI score, and the derived recommendation (pass / review / block).

Request body

FieldTypeDescription
audio_urlstring, requiredPublicly fetchable HTTPS URL to the audio file (MP3, WAV, FLAC, M4A). Signed Firebase / S3 URLs are fine.
metadataobject, optionalTrack metadata (see below). Helps local signals.
metadata.titlestringTrack title.
metadata.artiststringArtist name. Names matching AI-generator patterns boost local_score.
metadata.isrcstringISRC code.
metadata.duration_secondsintegerTrack duration in seconds.
client_track_idstring, optionalYour internal track ID (≀255 chars). Echoed back for correlation.

Example

POST https://api.distroshield.com/v1/analyze
Authorization: Bearer ds_...
Content-Type: application/json

{
  "audio_url": "https://firebasestorage.googleapis.com/.../track.wav?token=...",
  "metadata": {
    "title": "Mi Bello Puerto",
    "artist": "Juan PΓ©rez",
    "isrc": "USRC17607839",
    "duration_seconds": 187
  },
  "client_track_id": "mhm-2026-03296"
}

Response 200 OK

The response combines four independent quality signals β€” AI detection, duplicate check, metadata validation, and recording fingerprint β€” into a single recommendation. Details on each module below.

{
  "analysis_id": "an_8_2HwDlNC1f_",
  "db_id": 42,

  // ---- Module 1: AI detection ----
  "ai_score": 0.0655,
  "classification": "human",
  "classification_origin": "human",       // mirrors classification when not ai
  "origin_confidence": 0.9775,
  "confidence": 0.9775,
  "signals": {
    "local_score": 0.15,
    "local_reasons": ["missing_artist"],
    "model_score": 0.0373,
    "weights": { "local": 0.25, "model": 0.75 }
  },
  "model_version": "distroshield-v7c",
  "attribution_model_version": null,      // populated only when classification == "ai"

  // ---- Module 2: Duplicate check (only if metadata.isrc or title+artist given) ----
  "duplicate_score": 0,
  "duplicate_matches": [],
  "sources_checked": ["spotify", "deezer", "youtube"],

  // ---- Module 3: Metadata validation (only if metadata given) ----
  "metadata_validation": {
    "score": 0.95,
    "summary": { "high": 0, "medium": 0, "low": 1 },
    "issues": [
      { "severity": "low", "type": "ddex_missing_recommended",
        "detail": "Recommended field \"genre\" is missing" }
    ]
  },

  // ---- Module 4: Recording fingerprint (only if audio_url given) ----
  "recording_fingerprint": {
    "matched": false,
    "matches": [],
    "highest_score": 0,
    "distinct_artists_at_perfect_score": 0,
    "submitted_isrc_matched": false,
    "submitted_artist_matched": false,
    "review_reason": null
  },

  // ---- Combined decision ----
  "recommendation": "pass",
  "analyzed_at": "2026-04-24T16:27:01.742Z"
}

Response fields

FieldMeaning
ai_scoreFinal score 0.0–1.0 (ensemble of model + local signals). Higher = more likely AI.
classificationDerived from ai_score against your client thresholds: human, hybrid, or ai.
classification_originSub-attribution when AI is detected. One of: human, hybrid, suno_unlicensed (Suno-style β€” Warner deal Nov 2025, UMG/Sony pending), licensed_ai (Udio / ElevenLabs β€” major-label deals), unknown_ai (MusicGen / Stable Audio / Riffusion / unknown). When classification is human or hybrid, this mirrors that value. Informational only β€” the distribution / Content ID decision belongs to your policy.
origin_confidenceConfidence (0–1) in the classification_origin attribution.
attribution_model_versionOptional. Identifier of the attribution model that produced classification_origin (e.g. distroshield-v8-attribution). null when only the primary binary model ran.
confidenceHow confident the model is in the classification (0.0–1.0).
signalsBreakdown: model_score (pure ML), local_score (metadata rules), weights used.
recommendationpass (ship it), review (human-in-the-loop), or block (do not deliver to DSP). Upgraded from pass to review when a strong duplicate, high-severity metadata issue, or recording-fingerprint match is detected.
review_reasonSet when recommendation was upgraded from pass. One of: duplicate_detected, metadata_issue, recording_fraud_match, cross_distributor_recording_fraud.
duplicate_score0–1. Highest confidence that this track already exists somewhere public. See Duplicate check.
duplicate_matchesUp to 10 ranked matches from Spotify, Deezer, YouTube.
sources_checkedWhich DSPs were queried successfully.
metadata_validationPer-field issues + overall score. See Metadata validation.
recording_fingerprintAudio-hash match against 70M+ commercial recordings. Catches re-uploads with metadata changed. See Recording fingerprint.
db_idInternal integer ID. Use this to PATCH reviews or fetch later.
model_versionDetector version that scored this track. Pin to monitor drift.
⚠ Human-in-the-loop is mandatory. Never auto-reject a track without a human option to override. Tracks with recommendation: "block" should enter a review queue, not be deleted.

Response modules

Each /v1/analyze response is produced by four independent quality-control modules running in parallel. Each module is optional β€” fields appear only when the module ran:

Module 1
AI detection

Acoustic analysis of the audio itself (wav2vec2 fine-tuned on real AI / human catalogs). Always runs. Returns ai_score, classification, signals.

Module 2
Duplicate check

Cross-references ISRC and title+artist against Spotify, Deezer, YouTube in parallel. Runs when metadata has ISRC or title+artist. Returns duplicate_score, duplicate_matches.

Module 3
Metadata validation

ISRC format validation, DDEX completeness, identity fraud detection (ISRC belongs to someone else), artist-name impersonation checks. Runs when metadata is provided. Returns metadata_validation.

Module 4 Β· NEW
Recording fingerprint

Audio-hash match against 70M+ commercial recordings. Catches re-uploads with metadata changed and cross-distributor identity fraud. Runs when an audio URL is provided. Returns recording_fingerprint.

Module 2 Β· Duplicate check

Checks whether the track already exists in major public music sources. Executes when metadata.isrc OR both metadata.title and metadata.artist are provided. Skipped otherwise.

Sources

SourceISRC lookupTitle+artist search
Spotify Web APIβœ“ exactβœ“ fuzzy
Deezer public APIβœ“ exactβœ“ fuzzy
YouTube Data API v3β€”βœ“ fuzzy

Scoring

  • Exact ISRC match on any source β†’ match_score: 1.0
  • Fuzzy title+artist match (≥0.5) β†’ match_score: 0.5–1.0
  • duplicate_score is the top match's score + 5% boost per additional source that also matched

Example match

{
  "source": "spotify",
  "match_type": "isrc",        // or "title_artist"
  "match_score": 1.0,
  "id": "7qiZfU4dY1lWllzX7mPBI3",
  "title": "Shape of You",
  "artist": "Ed Sheeran",
  "url": "https://open.spotify.com/track/7qiZfU4dY1lWllzX7mPBI3"
}

Module 3 Β· Metadata validation

Validates the declared metadata across four dimensions. Runs locally (<10 ms) when metadata is provided.

Checks performed

CheckWhat it catches
ISRC formatStructure (12 chars: 2 letters + 3 alnum + 7 digits), country code validity, future-year detection.
DDEX completenessMandatory fields (title, artist) + recommended DDEX 4 fields (isrc, duration_seconds, album, genre, language, release_date). Missing recommended fields are consolidated into a single issue to avoid noise.
Identity fraudCross-references the declared title + artist against what Spotify / Deezer have registered under that ISRC. Catches the "I claim this ISRC as my new song" fraud where someone submits a track using another artist's ISRC.
Artist impersonationFuzzy match against a curated list of globally-famous + LATAM-top artists. Flags suspicious near-matches like "3d Sheeran" vs "Ed Sheeran".
Duration anomaly checksFlags duration-based fraud and anomaly patterns (including known Content ID abuse). Specific thresholds are kept private to avoid tipping off bad actors β€” legitimate tracks are not affected.

Issue structure

{
  "severity": "high",          // high | medium | low
  "type": "isrc_identity_artist_mismatch",
  "detail": "ISRC is registered on spotify as artist 'The Weeknd' but you declared 'Mi Artista'",
  "registered": {              // present on identity-mismatch only
    "source": "spotify",
    "artist": "The Weeknd",
    "title": "Blinding Lights",
    "url": "https://open.spotify.com/track/..."
  }
}

Scoring

metadata_validation.score starts at 1.0 and subtracts penalties: high -0.40, medium -0.15, low -0.05. Clamped to [0, 1]. Any high severity issue upgrades the overall recommendation from pass to review.

Module 4 Β· Recording fingerprint

Hashes the submitted audio and matches it against a catalog of 70M+ commercial recordings. Catches the case other modules are structurally blind to: a fraudster re-uploading someone else's exact recording with the metadata changed.

Executes when an audio_url is provided. Skipped otherwise.

Fields

FieldMeaning
matchedTrue when at least one recording in the catalog matches.
matchesUp to 10 ranked matches. Each contains title, artists, album, label, score (0–100), release_date, isrc, upc, plus direct URLs to spotify_url, deezer_url, youtube_url when available.
highest_scoreTop match's score (0–100). 100 = perfect audio match.
distinct_artists_at_perfect_scoreHow many different artist identities own a near-perfect (β‰₯95) match. β‰₯2 means the same recording is registered under multiple identities across distributors β€” per-se evidence of cross-distributor identity fraud.
submitted_isrc_matchedTrue when the ISRC in your metadata matches one of the ISRCs returned by the fingerprint match. Surfacing-only β€” does NOT downgrade the flag (a fraudster can copy any ISRC).
submitted_artist_matchedSame idea, for artist name.
review_reasonSet to cross_distributor_recording_fraud when 2+ distinct artists match at score β‰₯95, or recording_fraud_match when at least one match is at score β‰₯80. Otherwise null.
errorOptional. Set when the fingerprint backend returned an error (e.g. timeout, billing issue). The pipeline continues without this signal in that case.

Routing

  • β€’ A single match at score β‰₯80 sets review_reason to recording_fraud_match and upgrades recommendation from pass to review.
  • β€’ Two or more matches at score β‰₯95 with different artists takes precedence and sets review_reason to cross_distributor_recording_fraud β€” the highest-confidence form of fraud the API surfaces.
  • β€’ The signal never auto-blocks. Human-in-the-loop is mandatory.
POST /v1/batch

Batch analyze (async)

Submit many tracks at once. Returns a batch ID immediately; tracks are processed asynchronously by the worker queue. Results delivered via webhook (recommended) or polled via GET /v1/batch/:id.

Request body

{
  "tracks": [
    { "audio_url": "...", "metadata": {...}, "client_track_id": "..." },
    { "audio_url": "...", "metadata": {...}, "client_track_id": "..." }
  ],
  "webhook_url": "https://your-server.com/distroshield-webhook"
}

Response 200 OK

{
  "batch_id": 17,
  "track_count": 2,
  "status": "queued"
}

Each track result is POSTed to webhook_url with HMAC-SHA256 signature in X-DistroShield-Signature header.

GET /v1/analysis/:id

Retrieve a single analysis

Fetch a full analysis row by its db_id. Scoped to your client β€” you can only fetch analyses for tracks you own.

GET https://api.distroshield.com/v1/analysis/42
Authorization: Bearer ds_...

β†’ {
  "id": 42,
  "track_id": 58,
  "ai_score": "0.0655",
  "classification": "human",
  "confidence": "0.9775",
  "signals_json": "{...}",
  "model_version": "distroshield-v7c",
  "review_status": "none",
  "review_verdict": null,
  "reviewer_email": null,
  "reviewed_at": null,
  "review_notes": null,
  "analyzed_at": "2026-04-24T16:27:01.000Z",
  "client_id": 1
}
GET /v1/analyses

List analyses (review queue)

Paginated list of analyses for your client. Use the status query param to filter β€” this is how your review queue UI fetches pending items.

Query parameters

ParamDefaultValues
statuspendingnone, pending, reviewed, overridden, all
classificationβ€”human, hybrid, ai
limit50Integer 1–200
offset0Integer β‰₯0

Example

GET /v1/analyses?status=pending&classification=hybrid&limit=20
Authorization: Bearer ds_...

β†’ {
  "count": 20,
  "limit": 20,
  "offset": 0,
  "items": [
    {
      "id": 42,
      "ai_score": "0.5231",
      "classification": "hybrid",
      "model_version": "distroshield-v7c",
      "review_status": "pending",
      "analyzed_at": "2026-04-24T16:27:01.000Z",
      "track_id": 58,
      "title": "Track title",
      "artist": "Artist",
      "source_url": "https://..."
    },
    ...
  ]
}
PATCH /v1/analyses/:id/review

Record human verdict

After a reviewer decides whether a flagged track is actually AI or human, persist their verdict. These labels feed into future model retraining.

Request body

FieldTypeDescription
verdictstring, required
human β€” track is fully human-made
ai β€” track is fully AI-generated
uncertain β€” reviewer cannot decide
hybrid_confirmed β€” reviewer confirms the track legitimately mixes AI and human elements (e.g. AI-generated instruments with human vocals). Future model retraining uses this as a soft label so the model learns to produce intermediate scores instead of forcing every track into the binary human/ai decision.
notesstring, optional, nullableFree-text note about why (≀2000 chars). May be omitted or sent as null.
reviewer_emailstring, optional, nullableEmail of the person reviewing. May be omitted or sent as null; defaults to the client's contact_email.
PATCH https://api.distroshield.com/v1/analyses/42/review
Authorization: Bearer ds_...
Content-Type: application/json

{
  "verdict": "human",
  "notes": "Heavy autotune but definitely human β€” female reggaeton vocal",
  "reviewer_email": "j@mhmusik.com"
}

β†’ {
  "analysis_id": 42,
  "original_classification": "ai",
  "human_verdict": "human",
  "review_status": "overridden",
  "reviewer_email": "j@mhmusik.com",
  "reviewed_at": "2026-04-24T17:30:12.000Z"
}

review_status becomes overridden when the verdict disagrees with the model's original classification, else reviewed.

POST /v1/webhooks

Register a webhook

DistroShield will POST async analysis results to your URL. The secret returned is used to sign each delivery with HMAC-SHA256 β€” verify signatures to reject forgeries.

POST /v1/webhooks
Authorization: Bearer ds_...

{
  "url": "https://your-server.com/distroshield-webhook",
  "events": ["analysis.completed", "batch.completed"]
}

β†’ {
  "webhook_id": 3,
  "secret": "whsec_abc...",   // shown ONCE β€” store it securely
  "url": "https://...",
  "events": [...]
}

Each delivery retries with exponential backoff (30s β†’ 4d, up to 8 attempts) until your endpoint responds 2xx.

GET /v1/usage

Usage metrics

Current period API usage for your client. Use to monitor your quota.

GET /v1/usage
Authorization: Bearer ds_...

β†’ {
  "period_start": "2026-04-01T00:00:00Z",
  "period_end": "2026-04-30T23:59:59Z",
  "requests": { "analyze": 312, "batch": 4, "total": 316 },
  "analyses_by_classification": {
    "human": 287, "hybrid": 18, "ai": 11
  }
}

Error codes

Errors return JSON with an error code. Some include additional context.

StatusCodeMeaning
400invalid_bodyRequest body didn't match the schema. Check the issues array.
400invalid_queryQuery parameters didn't validate.
400invalid_analysis_idThe :id path parameter wasn't a positive integer.
401unauthorizedMissing, malformed, or invalid Bearer token.
404analysis_not_foundAnalysis ID doesn't exist OR doesn't belong to your client.
415unsupported_audio_formatThe audio file at audio_url could not be decoded. Response includes supported_formats array. Supported: WAV, FLAC, OGG, MP3, M4A, AAC.
429rate_limitedYou exceeded your rate limit window. Retry after the period resets.
500internal_errorUnexpected server error. Contact support with the request ID in response headers.
502audio_fetch_failedWe could not fetch the audio from the URL you provided. Check that the URL is reachable and not expired (e.g. signed URL TTL).
502inference_unavailableThe inference service is temporarily unavailable. Retry shortly.

Rate limits

Default: 300 requests per minute per API key. Response headers expose your current state:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
X-RateLimit-Reset: 60

Exceeding returns 429 rate_limited. Need higher limits? Contact us for Pro/Enterprise tiers.

Detection model

Current production version: distroshield-v7c. Trained on a curated mix of: real distributor-verified AI tracks, Suno / MusicGen-generated samples, and over 1,500 human tracks from a real distributor catalog spanning reggaetΓ³n, latin pop, dembow, regional mexicano, cristiano/gospel, electronic, hip-hop, bachata, cumbia, folk and other Latin American styles. Continuously improved from production review verdicts.

Ground-truth accuracy
90%
on hand-picked verified tracks
Recall against real-world AI
90%+
Suno / Udio / MusicGen / voice cloning

Scores are probabilistic. Human-in-the-loop review is mandatory. Never auto-block tracks without a human override path β€” the API is a gate, not a judge.