Why track a label?
If you follow a label like Drumcode, Anjunadeep, or mau5trap, you want to know the moment new music drops — not discover it weeks later in a playlist algorithm. The SonoVault API gives you two endpoints that, combined, turn any label into a live release feed.
/v1/labels/search— find a label by name and get its ID/v1/labels/:id— get the full catalog: releases and tracks, sorted by release date (newest first)
That's all you need. Search once to get the ID, then poll the detail endpoint on a schedule. New releases appear at the top.
Find the label
Search by name. The response includes the label ID and how many releases it has. Exact matches sort first, then by release count — so searching "Drumcode" returns the right one immediately.
{
"results": [{
"id": 482,
"name": "Drumcode",
"release_count": 842
}],
"nextCursor": null
}Get the catalog
Pass the label ID to the detail endpoint. You get back the label info, all releases (with artist name, date, and track count), and all tracks (with ISRC, genres, and artist credits). Both releases and tracks are sorted by release date, newest first.
{
"label": {
"id": 482,
"name": "Drumcode"
},
"releases": [
{
"id": 9102,
"title": "Drumcode 300",
"artist_id": 155,
"artist_name": "Adam Beyer",
"release_date": "2026-03-28",
"track_count": 12
}
],
"tracks": [
{
"id": 78201,
"title": "Pressure",
"isrc": "SE2026000123",
"artists": [{ "name": "Adam Beyer", "is_primary": true }],
"genres": [{ "name": "Techno" }]
}
]
}Display recent releases
The releases array is already sorted by date. Slice the first 10 for a "latest releases" view, or filter by date range to show only this week's drops.
Here's the complete script — search, fetch, and display in under 50 lines:
const API_KEY = process.env.SONOVAULT_API_KEY!; const BASE = "https://api.sonovault.now/v1"; interface LabelSearchResult { id: number; name: string; release_count: number; } interface Release { id: number; title: string; artist_name: string; release_date: string; track_count: number; } interface Track { id: number; title: string; isrc: string | null; artists: { name: string; is_primary: boolean }[]; genres: { name: string }[]; release_id: number; release_title: string; } async function api(path: string) { const res = await fetch(`${BASE}${path}`, { headers: { "x-api-key": API_KEY }, }); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); return res.json(); } // Step 1: Find the label const { results } = await api("/labels/search?name=Drumcode"); const label = results[0] as LabelSearchResult; console.log(`Found: ${label.name} (id: ${label.id}, ${label.release_count} releases)`); // Step 2: Get the full catalog const detail = await api(`/labels/${label.id}`); const releases = detail.releases as Release[]; const tracks = detail.tracks as Track[]; // Step 3: Show recent releases console.log(`\nLatest releases from ${label.name}:\n`); releases.slice(0, 10).forEach((r) => { console.log( ` ${r.release_date} ${r.artist_name} — ${r.title} (${r.track_count} tracks)` ); }); // Step 4: Show recent tracks with metadata console.log(`\nLatest tracks:\n`); tracks.slice(0, 20).forEach((t, i) => { const artist = t.artists.find(a => a.is_primary)?.name ?? t.artists[0]?.name; const genre = t.genres[0]?.name ?? ""; console.log( ` ${i + 1}. ${artist} — ${t.title}${genre ? ` [${genre}]` : ""}` ); });
Detect new releases on a schedule
To get notified when new tracks appear, run the script on a daily cron and compare against a stored list of previously seen track IDs. New IDs = new releases.
import fs from "node:fs"; const LABEL_ID = 482; // Drumcode const STATE_FILE = "./last-seen.json"; // Load previously seen track IDs const seen: Set<number> = new Set( fs.existsSync(STATE_FILE) ? JSON.parse(fs.readFileSync(STATE_FILE, "utf-8")) : [] ); // Fetch current catalog const detail = await api(`/labels/${LABEL_ID}`); const tracks = detail.tracks as Track[]; // Find new tracks const newTracks = tracks.filter(t => !seen.has(t.id)); if (newTracks.length > 0) { console.log(`${newTracks.length} new track(s) on Drumcode:\n`); newTracks.forEach(t => { const artist = t.artists.find(a => a.is_primary)?.name; console.log(` ${artist} — ${t.title}`); }); // Send a webhook, email, Slack message, etc. // await notify(newTracks); } // Save current state fs.writeFileSync(STATE_FILE, JSON.stringify(tracks.map(t => t.id)));
Going further
Once the basics are running, a few natural extensions:
- Track multiple labels. Store an array of label IDs and loop through them in your cron. Each label costs one API call.
- Filter by genre. The tracks in the response include genre tags. Filter client-side to surface only the styles you care about.
- Build a release calendar. Group releases by date to create a visual timeline of upcoming and recent drops across all your tracked labels.
- Combine with browse.Once you know a label's ID, use the browse endpoint with
labelIdto surface tracks by genre and year from a single label's catalog.
Frequently asked questions
How do I find a label's ID?
Use the /v1/labels/search endpoint with the label name. The response includes the label ID, which you then pass to /v1/labels/:id for the full catalog.
How often is label data updated?
New releases are imported daily. The label detail endpoint always returns the latest catalog, so polling once a day is sufficient to catch new drops.
Is there a limit on how many tracks are returned?
The label detail endpoint returns up to 500 tracks, sorted by release date (newest first). For most labels this covers the full catalog. For very large labels, you get the 500 most recent tracks.
Can I track multiple labels at once?
Yes — search for each label, store the IDs, and poll each one on a schedule. The endpoints are lightweight enough to check dozens of labels in a single cron run.