# API reference

> Sound Server API 0.1.0: every endpoint, parameter and response. Machine-readable: https://sound.shep.bot/openapi.json

## GET /v1/search

Search every source (`searchSamples`)

Fans out to every enabled source in parallel (each with its own timeout), then merges and ranks. Words like `140 bpm`, `F minor` or `one shot` in `q` become filters (see `filters` in the response); explicit parameters win. Unknown BPM, key, form or duration stay in the list, ranked below known matches, unless `strict=true`. A slow or failing source never fails the search: it shows up in `providers` with its status.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `q` | query | string | Short query, written like a producer would. |
| `category` | query | string | Comma-separated categories; a parent includes its children. Top level: drums, bass, vocals, fx, foley, ambience, keys, guitar, synth, strings, brass, woodwind, mallets, other; children like `drums.kick`, `bass.808`, `vocals.chop`, `fx.riser`. |
| `form` | query | string | Comma-separated forms: one-shot, loop, phrase, multisample, pack, midi, preset. |
| `bpm` | query | string | Tempo or range: "140" or "120-128". |
| `key` | query | string | Musical key: "F minor", "F#m", "Eb", "A major". |
| `min_duration` | query | number | Minimum length in seconds. |
| `max_duration` | query | number | Maximum length in seconds (e.g. 2 for one-shots). |
| `commercial` | query | boolean | Only samples whose licence verdict is `yes` or `yes-with-credit`. |
| `free` | query | boolean | Only free samples. |
| `downloadable` | query | boolean | Only samples this server can download directly. |
| `strict` | query | boolean | Drop samples whose BPM, key, form or duration is unknown when that filter is set. |
| `providers` | query | string | Comma-separated source ids (see /v1/providers). |
| `limit` | query | integer | Max results (default 24). |
| `offset` | query | integer | Per-source offset for paging (e.g. 24 for page 2). |
| `x-freesound-token` | header | string | Optional: your own Freesound OAuth2 access token. Freesound serves its original WAV/AIFF/FLAC files only to a logged-in user, so without it Freesound samples download as their high-quality MP3/OGG preview. The token is passed to Freesound for this request only and is never logged or stored. |

Responses: `200` Ranked results, the filters in force and a per-source report. (SearchResponse); `400` Invalid parameters or unknown source id. (Error); `401` API key required (self-hosted servers only). (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/search?category=drums.kick&form=one-shot&bpm=140&key=F%20minor&providers=freesound%2Cwikimedia"
```

## GET /v1/samples/{id}

Sample details with files (`getSample`)

Full metadata, the licence with its verdict and credit line, the preview and every file for one sample.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Sample id `<provider>:<nativeId>`, URL-encoded (`:` may stay as is). Take it from a search result. |
| `x-freesound-token` | header | string | Optional: your own Freesound OAuth2 access token. Freesound serves its original WAV/AIFF/FLAC files only to a logged-in user, so without it Freesound samples download as their high-quality MP3/OGG preview. The token is passed to Freesound for this request only and is never logged or stored. |

Responses: `200` The sample and its files. (SampleDetails); `400` Malformed id or unknown source. (Error); `404` Unknown sample. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error); `501` The source has no detail pages here; open `url` on the source site. (Error); `502` The source site failed. (Error)

```bash
curl "https://sound.shep.bot/v1/samples/freesound:2086"
```

## GET /v1/samples/{id}/files

Pick the right files (`selectFiles`)

The best file for a format and role (the original WAV by default), or every file with `all=true`, with sizes and the licence.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Sample id `<provider>:<nativeId>`, URL-encoded (`:` may stay as is). Take it from a search result. |
| `format` | query | string | Preferred file format. The closest match wins; omitted = the best quality available (WAV, then AIFF, FLAC, OGG, MP3). |
| `role` | query | "original" \| "preview" \| "pack" \| "stem" \| "midi" | Which kind of file: the `original` upload, the `preview`, a `pack` archive, a `stem` or `midi` part of a construction kit. |
| `all` | query | boolean | Every file instead of the best single one. |
| `x-freesound-token` | header | string | Optional: your own Freesound OAuth2 access token. Freesound serves its original WAV/AIFF/FLAC files only to a logged-in user, so without it Freesound samples download as their high-quality MP3/OGG preview. The token is passed to Freesound for this request only and is never logged or stored. |

Responses: `200` Selected files and total size. (FileSelection); `404` Unknown sample. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/samples/freesound:2086/files?format=wav"
```

## GET /v1/samples/{id}/download

Download (`downloadSample`)

One plain file redirects (302) to the source, so the bytes never pass through this server. Several files, files the source only serves with extra request headers, or `bundle=true` stream as one zip with `ATTRIBUTION.md` and `credits.json` next to the audio. `X-License` and `X-Attribution` carry the licence on both. Samples that are only available on the source site (an account, a purchase, a login wall) answer 409 with the page `url`.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Sample id `<provider>:<nativeId>`, URL-encoded (`:` may stay as is). Take it from a search result. |
| `format` | query | string | Preferred file format. The closest match wins; omitted = the best quality available (WAV, then AIFF, FLAC, OGG, MP3). |
| `role` | query | "original" \| "preview" \| "pack" \| "stem" \| "midi" | Which kind of file: the `original` upload, the `preview`, a `pack` archive, a `stem` or `midi` part of a construction kit. |
| `all` | query | boolean | Every file instead of the best single one. |
| `bundle` | query | boolean | Always answer with a zip that includes ATTRIBUTION.md and credits.json. |
| `x-freesound-token` | header | string | Optional: your own Freesound OAuth2 access token. Freesound serves its original WAV/AIFF/FLAC files only to a logged-in user, so without it Freesound samples download as their high-quality MP3/OGG preview. The token is passed to Freesound for this request only and is never logged or stored. |

Responses: `200` Zip bundle with the files, ATTRIBUTION.md and credits.json. (string (binary)); `302` Redirect to the single file on the source.; `404` Unknown sample or no file matches the format/role. (Error); `409` No direct download here; get the file from the source page (`url`). (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -L -O "https://sound.shep.bot/v1/samples/freesound:2086/download?format=wav"
```

## GET /v1/samples/{id}/preview

Play the preview (`getPreview`)

Redirects (302) to the sample's preview. Previews the source only serves with a Referer, and any preview with `proxy=1`, are streamed through this server with `Access-Control-Allow-Origin: *`, so browser players, Strudel and web DAWs can load them. Previews only, at most 25 MB: this is not a general proxy.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Sample id `<provider>:<nativeId>`, URL-encoded (`:` may stay as is). Take it from a search result. |
| `proxy` | query | boolean | Stream the preview through this server (CORS enabled) instead of redirecting. |
| `x-freesound-token` | header | string | Optional: your own Freesound OAuth2 access token. Freesound serves its original WAV/AIFF/FLAC files only to a logged-in user, so without it Freesound samples download as their high-quality MP3/OGG preview. The token is passed to Freesound for this request only and is never logged or stored. |

Responses: `200` The preview audio. (string (binary)); `302` Redirect to the preview on the source.; `404` Unknown sample, or it has no preview. (Error); `413` Preview too large to proxy. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/samples/freesound:2086/preview"
```

## GET /v1/samples/{id}/peaks

Waveform peaks (`getPeaks`)

Min/max pairs (-1..1) for drawing the sample's waveform, computed from its preview and cached. Pass them to wavesurfer.js as `peaks` with `duration`.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Sample id `<provider>:<nativeId>`, URL-encoded (`:` may stay as is). Take it from a search result. |
| `points` | query | integer | Number of min/max pairs (50–4000, default 800). |

Responses: `200` Peaks. (object); `404` Unknown sample, or no audio file to analyse. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/samples/freesound:2086/peaks"
```

## GET /v1/samples/{id}/similar

Sounds like this one (`findSimilar`)

Nearest sounds by audio embedding (CLAP) among the samples this server has indexed, when embeddings are turned on; otherwise Freesound's own similarity for `freesound:` ids. `method` says which was used.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Sample id `<provider>:<nativeId>`, URL-encoded (`:` may stay as is). Take it from a search result. |
| `limit` | query | integer | Max results (default 12, max 30). |

Responses: `200` Similar samples. (object); `404` Unknown sample. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error); `501` Embeddings are off on this server and the sample is not from Freesound. (Error)

```bash
curl "https://sound.shep.bot/v1/samples/freesound:2086/similar"
```

## GET /v1/samples/{id}/midi

MIDI from a melodic sample (`extractMidi`)

Transcribes a melodic sample (bass line, lead, arpeggio, vocal line) one note at a time and returns a Standard MIDI File, or the notes as JSON with `format=json`. Notes snap to the grid when the tempo is known (`bpm`, or the sample's own). Chords and drums are not transcribed; a warning says so.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Sample id `<provider>:<nativeId>`, URL-encoded (`:` may stay as is). Take it from a search result. |
| `bpm` | query | number | Tempo of the loop (40–300). |
| `quantize` | query | string | Steps per beat: 1, 2, 4 (16ths, default) or 8; `false` keeps the played timing. |
| `format` | query | "json" | `json` for the notes instead of the file. |

Responses: `200` The MIDI file, or the notes. (string (binary)); `400` Invalid bpm or quantize. (Error); `404` Unknown sample. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/samples/freesound:2086/midi"
```

## GET /v1/embeddings

Embedding index status (`embeddingsStatus`)

Whether audio embeddings are on, the model, how many samples are indexed and the indexing queue.

Responses: `200` Status. (object); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/embeddings"
```

## POST /v1/kits

Build a drum kit (`buildKit`)

One search per slot (default kick, snare, clap, closed hat, open hat, 808), steered by `style`, `bpm` and `key`, returning the best pick per slot with alternatives and the reason it won. Commercial-safe picks only unless `commercialOnly: false`. The response includes a Strudel sample map and snippet that play the picks through this server's preview proxy, a General MIDI / SFZ drum map, how many picks fall under each licence verdict, and the credit lines.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `x-freesound-token` | header | string | Optional: your own Freesound OAuth2 access token. Freesound serves its original WAV/AIFF/FLAC files only to a logged-in user, so without it Freesound samples download as their high-quality MP3/OGG preview. The token is passed to Freesound for this request only and is never logged or stored. |

Responses: `200` The kit plan. (Kit); `400` Invalid body (e.g. an unreadable key). (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -X POST "https://sound.shep.bot/v1/kits" \
  -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{}'
```

## GET /v1/providers

List sources (`listProviders`)

Every sample site with the categories it carries, pricing, licence, the filters it applies itself and whether files can be downloaded directly.

Responses: `200` Sources. (object); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/providers"
```

## GET /v1/catalog

Catalog census (`getCatalog`)

How many samples every source holds, counted once a day: listings per source, by top-level category, licence and the source's own categories, free counts, listings added in the last 30 days, and highlights such as the most downloaded sample. `atLeast: true` marks lower bounds (sources that cap their counts). Sources whose count failed today keep their last good numbers with `stale`. The same file is at `/catalog.json`; one point per day is in `/catalog-history.json`.

Responses: `200` Catalog census. (Catalog); `404` The census has not been built on this server. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/catalog"
```

## GET /v1/stats

Usage statistics (`getStats`)

Aggregate usage of this server: searches by surface (web, API, MCP), downloads, MCP tool calls, the client families and categories searched most, and per-source health (success rate, p50/p95 latency). Counts come from Prometheus (`source: prometheus`, last 24 hours and 7 days) or, when it is unavailable, from this process since it started (`source: process`). No queries, IPs or user agents are exposed. Cached for 60 seconds.

Responses: `200` Usage statistics. (Stats); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://sound.shep.bot/v1/stats"
```

## POST /mcp

MCP endpoint (Streamable HTTP) (`mcp`)

Stateless Model Context Protocol endpoint for AI agents. Tools: `search_samples`, `get_sample`, `build_kit`, `find_similar`, `list_sources` (and `download_sample` on local installs, which saves files with their credits). Point any MCP client at this URL; see /docs/mcp for per-client setup.

Responses: `200` JSON-RPC 2.0 response. (object); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -X POST "https://sound.shep.bot/mcp" \
  -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_samples","arguments":{"query":"punchy kick","categories":["drums.kick"],"commercial_only":true}}}'
```

## GET /health

Health check (`health`)

Responses: `200` OK (object)

```bash
curl "https://sound.shep.bot/health"
```

## GET /openapi.json

This OpenAPI document (`openapi`)

Responses: `200` OpenAPI 3.1 (object)

```bash
curl "https://sound.shep.bot/openapi.json"
```

Schemas: Category, SampleForm, CommercialVerdict, NativeFilter, MusicalKey, License, Price, Sample, SampleFile, SampleDetails, SampleFilters, ProviderSearchReport, SearchResponse, Provider, FileSelection, KitRequest, KitSample, KitSlot, Kit, CountWithBound, SourceCensus, Catalog, UsageWindow, Ranked, ProviderHealth, Stats, Error. See https://sound.shep.bot/openapi.json.

---
Source: https://sound.shep.bot/docs/api/reference
