Sound Server REST API guide
A small JSON API over HTTPS. No key is needed on https://sound.shep.bot. Every endpoint is described in the OpenAPI 3.1 spec, which you can explore and try in the interactive reference.
Base URL: https://sound.shep.bot
The flow
GET /v1/search: find candidates across every source.GET /v1/samples/{id}: read the licence verdict, credit line, musical facts and files of one result.GET /v1/samples/{id}/download: get the file, or a zip with the credits.
Plus GET /v1/samples/{id}/preview to play a preview from a browser or Strudel, and POST /v1/kits to assemble a drum kit in one call.
Search
curl "https://sound.shep.bot/v1/search?q=punchy+kick&category=drums.kick&form=one-shot&commercial=true&limit=10"
| Parameter | Description |
|---|---|
q |
Free text, written like a producer would: punchy kick, dusty snare, vocal chop 140 bpm, 808 in F minor. BPM, key and form words become filters. May be empty when category is set (browse). |
category |
Comma-separated dot-path categories. A parent matches its children: drums matches drums.kick and drums.hat.closed. See the Category schema for the full list (drums.kick, drums.snare, drums.clap, drums.hat.closed, bass.808, vocals.chop, fx.riser, fx.impact, foley, ambience, keys, synth.pad…). |
form |
Comma-separated: one-shot, loop, phrase, multisample, pack, midi, preset. |
bpm |
140 or a range 120-128. Half and double time also match. |
key |
F minor, F#m, Eb, A major. Relative major/minor also match. |
min_duration, max_duration |
Length in seconds (e.g. max_duration=2 for drum one-shots). |
commercial |
true: only samples whose licence allows a commercial release (verdict yes or yes-with-credit). |
free |
true: exclude paid samples and packs. |
downloadable |
true: only samples this server can download directly. |
strict |
true: drop samples whose BPM, key or form is unknown when you filter on them (by default they are kept, ranked lower). |
providers |
Comma-separated source ids from /v1/providers, e.g. freesound,openverse. |
limit |
Max results, 1–100 (default 24). |
offset |
Per-source offset for the next page (e.g. 24). |
The response (shortened):
{
"query": "punchy kick",
"filters": { "categories": ["drums.kick"], "forms": ["one-shot"], "commercialOnly": true },
"results": [
{
"id": "freesound:2086",
"provider": "freesound",
"title": "Punchy Kick 01",
"url": "https://freesound.org/s/2086/",
"author": "someone",
"category": "drums.kick",
"form": "one-shot",
"durationSec": 0.42,
"previewUrl": "https://cdn.freesound.org/previews/2/2086_23-hq.mp3",
"license": {
"id": "CC-BY-4.0", "name": "CC BY 4.0", "assertedBy": "source",
"attributionRequired": true, "verdict": "yes-with-credit",
"note": "Credit the author in your release notes or description."
},
"attribution": "“Punchy Kick 01” by someone (Freesound), https://freesound.org/s/2086/, licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)",
"requiresAccount": true,
"downloadable": true
}
],
"providers": [
{ "provider": "freesound", "name": "Freesound", "status": "ok", "count": 10, "total": 1843, "tookMs": 412 },
{ "provider": "splice", "name": "Splice", "status": "link", "count": 0, "searchUrl": "https://splice.com/sounds/search?q=punchy+kick" }
]
}
Licence verdicts
Every license has a verdict that answers one question: can this go into a commercially released track?
verdict |
Meaning |
|---|---|
yes |
Commercial use OK, no credit required (CC0, public domain, royalty free). |
yes-with-credit |
Commercial use OK with a credit line: use attribution. |
restricted |
Conditions that usually rule out a normal release (share-alike, Sampling+). |
clearance-required |
A real recording that needs paid clearance per release. |
check-terms |
Unclear: no licence stated, uploader-asserted, or subscription terms. |
no |
Non-commercial only. |
license.assertedBy says who stated it: source (the site records it per item), site (one licence for the whole site) or uploader (an unverified claim; such licences are never better than check-terms). More in Sample licences explained.
Sample details
curl "https://sound.shep.bot/v1/samples/freesound:2086"
Returns the sample plus files[] (each with url, filename, format, role (original, preview, pack, stem, midi), sampleRate, bitDepth, channels, sizeBytes, and requiresAuth when it needs an account on the source) and a shareUrl that opens it on the website.
Choose files
curl "https://sound.shep.bot/v1/samples/freesound:2086/files?format=wav"
The files a download would contain for a format (wav, aiff, flac, ogg, mp3, zip) or role, with totalBytes, the licence and the credit line. all=true returns everything.
Download
curl -L -o kick.zip "https://sound.shep.bot/v1/samples/freesound:2086/download?bundle=true"
A single plain file answers with a 302 redirect to the source (so use -L). Several files, files that need source headers, or bundle=true stream one zip with ATTRIBUTION.md and credits.json next to the audio. The response carries X-License and X-Attribution headers. Samples without direct downloads answer 409 with the sample’s url and requiresAccount. The original from Freesound needs a Freesound account: send your own OAuth token as x-freesound-token, otherwise only the preview is available.
Previews
curl -L "https://sound.shep.bot/v1/samples/freesound:2086/preview" -o preview.mp3
Redirects to the source’s preview. Sources whose previews need a Referer, or ?proxy=1, are streamed through this server with Access-Control-Allow-Origin: *, so browser players, Web Audio and Strudel can load them. Only previews are proxied, capped in size: this is not a general proxy.
Build a kit
curl -X POST "https://sound.shep.bot/v1/kits" -H "content-type: application/json" \
-d '{"style":"dark trap","bpm":140,"key":"F minor","slots":["kick","snare","clap","hat.closed","hat.open","808"]}'
One pick per slot with alternatives and the reason it was chosen, warnings, a count of picks per verdict, the credit lines, a Strudel sample map and snippet (pointing at the preview proxy, so it plays in strudel.cc as is) and a General MIDI / SFZ drum map. commercialOnly defaults to true; perSlot sets the number of alternatives (0–5). The kit builder is a page on top of this endpoint.
List sources
curl "https://sound.shep.bot/v1/providers"
Usage statistics and source health
curl "https://sound.shep.bot/v1/stats"
Aggregate usage (searches by surface, downloads, MCP tool calls, top clients and categories) for the last 24 hours and 7 days, plus each source’s success rate and p50/p95 latency. The same data is on the statistics page. GET /v1/catalog returns the daily count of what each source holds.
Examples
JavaScript / TypeScript
const base = "https://sound.shep.bot";
const res = await fetch(`${base}/v1/search?` + new URLSearchParams({ q: "riser", category: "fx.riser", commercial: "true" }));
const { results } = await res.json();
const pick = results.find((s) => s.downloadable);
console.log(pick.title, pick.license.verdict, pick.attribution ?? "no credit needed");
new Audio(`${base}/v1/samples/${encodeURIComponent(pick.id)}/preview`).play();
Python
import requests
base = "https://sound.shep.bot"
r = requests.get(f"{base}/v1/search", params={"q": "808", "key": "F minor", "commercial": "true"})
sample = next(s for s in r.json()["results"] if s["downloadable"])
with requests.get(f"{base}/v1/samples/{sample['id']}/download", params={"bundle": "true"}, stream=True) as dl:
dl.raise_for_status()
with open("808.zip", "wb") as f:
for chunk in dl.iter_content(1 << 16):
f.write(chunk)
Errors
Errors are JSON: { "error": "message" }.
| Status | Meaning |
|---|---|
400 |
Bad parameter (e.g. an unreadable bpm or key) or unknown source id. |
401 |
API key required (self-hosted servers with SOUND_SERVER_API_KEY only). |
404 |
Unknown sample, or no file matches the format/role. |
409 |
The source has no direct downloads; use the returned url. |
429 |
Rate limit exceeded; wait Retry-After seconds. |
502 |
The source site failed. |
Authentication (self-hosted)
The public server is open. If you run your own with SOUND_SERVER_API_KEY, send the key as Authorization: Bearer <key> or x-api-key: <key>. Keys are accepted in headers only, never as a URL parameter, so they stay out of logs, browser history and Referer headers.
Rate limits and versioning
The public server allows 120 requests per minute per client. Every response carries RateLimit-Policy and RateLimit headers (plus RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset); going over returns 429 with Retry-After. The API is versioned in the path (/v1), only grows additively within a version, and announces deprecations with Deprecation and Sunset headers at least 90 days ahead. Details: Versioning, deprecation & rate limits.
Fair use
Cache results on your side for repeated queries, keep requests to a human pace, and respect each sample’s licence. The server already caches source responses for a few minutes and deduplicates identical in-flight requests. Sound Server is a free, non-commercial service and does not re-host or resell sounds.
AI agent? This page is also available as markdown.