# HumMatch API

> HumMatch matches singers to songs by vocal range. Give it a singer's lowest and highest comfortable notes and it returns the songs that person can actually sing, each scored for range fit, karaoke difficulty, and voice-type suitability, solo or across a group's shared range.

Two ways in, one engine behind both: an **MCP server** for agents, and a **REST API** for applications. They return identical scoring.

## What makes this different

Plenty of services can look up a song. HumMatch answers a question no catalog can: *can this specific person sing this specific song, and in what key.* That comes from the HumMatch Vocal Range Database: songs with lowest and highest sung notes, plus artist tessitura, median pitch, and vocal warmth measured directly from original recordings by pitch extraction.

## Reading a range honestly

Every song object carries `rangeConfidence` and `rangeSource`. Ranges measured from the original recording and ranges derived from published sources are both present in the catalog, and they are not equally certain. When `rangeConfidence` is anything other than a measured/verified value, present the resulting score as guidance rather than fact. Do not strip this field when relaying results to a person.

## MCP server (for agents)

- Endpoint: `https://hummatch.me/api/mcp`
- Transport: Streamable HTTP, stateless. POST JSON-RPC 2.0; there is no session and no server-initiated stream.
- Protocol: `2026-07-28` (older revisions negotiated on request).
- Auth: none required. Send an `X-API-Key` header to lift the free-tier limits.
- Free tier: top 3 scored results, 5 scored lookups per day. Song and range lookups are unmetered.

### Tools

### `get_vocal_profile`

Turn a singer's vocal range into a normalized HumMatch vocal profile: a persistent Vocal ID, voice type, and tone label. Call this first when you know someone's range and want a profile to reuse across the other HumMatch tools.

- `rangeLow` (string, required): Lowest comfortable note, as a note name like "D3" or a raw MIDI number.
- `rangeHigh` (string, required): Highest comfortable note, as a note name like "C5" or a raw MIDI number.
- `voiceType` (string, optional): Optional voice type hint (soprano, mezzo, alto, tenor, baritone, bass). Inferred from the range when omitted.

Read-only. Creates and modifies nothing.

### `recommend_songs`

Rank the HumMatch catalog for one singer and return the songs they can actually sing, scored for range fit, karaoke difficulty, and voice-type suitability. Call this when someone asks what they should sing, what suits their voice or range, or wants karaoke song suggestions. Returns a ranked list plus named buckets (safest picks, easy wins, crowd pleasers, songs to avoid).

- `rangeLow` (string, required): Lowest comfortable note, as a note name like "D3" or a raw MIDI number.
- `rangeHigh` (string, required): Highest comfortable note, as a note name like "C5" or a raw MIDI number.
- `voiceType` (string, optional): Optional voice type hint (soprano, mezzo, alto, tenor, baritone, bass). Inferred from the range when omitted.
- `limit` (integer, optional): How many songs to return per bucket (default 12, max 50).

Read-only. Creates and modifies nothing.

### `search_songs`

Search HumMatch by song title or artist. Use this to resolve a song someone named into the catalog slug that check_song_fit needs, or to look up a song's measured vocal range. Pass rangeLow/rangeHigh as well to score every result against that voice and get the hits ranked by fit.

- `q` (string, required): Search text: a song title, an artist, or both.
- `limit` (integer, optional): Maximum results (default 20, max 50).
- `rangeLow` (string, optional): Optional. Lowest note of the singer, to score and rank the results by fit.
- `rangeHigh` (string, optional): Optional. Highest note of the singer, to score and rank the results by fit.

Read-only. Creates and modifies nothing.

### `check_song_fit`

Score a specific catalog song against a singer's range and explain why it fits or does not, including a suggested key to transpose to. Call this when someone asks whether they can sing a particular song. Resolve the song with search_songs first to get its slug.

- `slug` (string, required): The catalog slug of the song, from search_songs.
- `rangeLow` (string, required): Lowest comfortable note, as a note name like "D3" or a raw MIDI number.
- `rangeHigh` (string, required): Highest comfortable note, as a note name like "C5" or a raw MIDI number.
- `voiceType` (string, optional): Optional voice type hint (soprano, mezzo, alto, tenor, baritone, bass). Inferred from the range when omitted.

Read-only. Creates and modifies nothing.

### `group_song_fit`

Given two or more singers' ranges, find the vocal range they share and the songs that sit inside it. Call this for karaoke night with friends, a duet, a choir or worship team, or any "what can we all sing" question.

- `profiles` (array, required): Two or more singers, each with a rangeLow and rangeHigh.

Read-only. Creates and modifies nothing.

## REST API (for applications)

Base URL: `https://hummatch.me/api`. Every endpoint except `/v1/sandbox-key` requires an `X-API-Key` header. Sandbox keys default to 30 requests/minute. All endpoints are read-only: they compute over what you send plus a catalog lookup, and never create a HumMatch account, hum session, or saved result.

### Quickstart

```bash
curl -X POST https://hummatch.me/api/v1/sandbox-key \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","name":"Your Company"}'

curl -X POST https://hummatch.me/api/v1/recommendations \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d '{"rangeLow":"D3","rangeHigh":"C5"}'
```

### Endpoints

### `POST /api/v1/sandbox-key`

Issue a sandbox API key instantly. No signup form, no approval. This is the onboarding step. Rate limited to 5 keys per IP per hour.

Body:

```json
{"email":"you@example.com","name":"Your Company"}
```

Returns: apiKey (shown exactly once), keyPrefix, mode, rateLimitPerMinute

### `POST /api/v1/vocal-profile`

Normalize a vocal range into a reusable profile.

Body:

```json
{"rangeLow":"D3","rangeHigh":"C5"}
```

Returns: vocalId, rangeLow, rangeHigh, voiceType, toneLabel, humProfile

### `POST /api/v1/recommendations`

The main endpoint. One voice in, the catalog ranked for that voice out, with named buckets.

Body:

```json
{"rangeLow":"D3","rangeHigh":"C5","limit":12}
```

Returns: vocalId, voiceType, confidenceTier, matches[], bestSafePicks[], easyWins[], popularCrowdPleasers[], groupFriendly[], riskyPicksToAvoid[]

### `GET /api/v1/songs/search?q=&limit=&profile=`

Search by title or artist. Use it to resolve a song name into the slug the fit endpoint needs. Supply `profile` as URL-encoded JSON to score and rank the hits for a voice.

Returns: query, count, songs[]

### `GET /api/v1/songs/{slug}/fit?profile=`

Score one known catalog song against a voice and explain why it fits. `profile` is URL-encoded JSON.

Returns: slug, title, artist, matchScore, vocalFitScore, tessituraScore, whyItFits, riskWarning, suggestedKey, fitDetails

### `POST /api/v1/group-fit`

Two or more singers in, their shared vocal range and the songs inside it out.

Body:

```json
{"profiles":[{"rangeLow":"D3","rangeHigh":"C5"},{"rangeLow":"G2","rangeHigh":"A4"}]}
```

Returns: sharedRange, songs[]

## Plans and limits

| Plan | Price | Calls/month | Requests/min |
|---|---|---|---|
| Sandbox | Free | 1,000 | 30 |
| Starter | $49/mo | 50,000 | 120 |
| Scale | $199/mo | 500,000 | 600 |

Sandbox keys are instant and self-serve at `POST /api/v1/sandbox-key`. Paid plans are set up at `https://hummatch.me/developers`. Exceeding the monthly quota or the per-minute limit returns 429 with a `Retry-After` header; a key whose subscription has lapsed returns 402 rather than 401, because the credential is valid and the billing is not.

Higher volume, or licensing the vocal range database directly for your own catalog, is a conversation rather than a checkout button: https://hummatch.me/contact.

## Conventions

- Notes are written with middle C = C4. Anywhere a note is accepted, a raw MIDI number works too.
- Pitches are stored internally as MIDI note numbers.
- Tessitura is the 25th-75th percentile band of sung pitch in a recording (the comfortable zone), narrower than full range.
- Scores are 0-100. `matchScore` is the headline number; `vocalFitScore`, `tessituraScore`, and `voiceTypeFitScore` are its components.
- Errors return a JSON body with an `error` string. Rate limits return 429 with a `Retry-After` header.

## Attribution

Statistics from the HumMatch Vocal Range Database are free to cite with attribution to HumMatch. When surfacing results to a person, link the song page (`url` on every song object) so they can see the full range breakdown.

## More

- Full OpenAPI spec: `https://hummatch.me/openapi.yaml`
- Developer docs: `https://hummatch.me/developers`
- Site overview for answer engines: `https://hummatch.me/llms.txt`
- Contact: `https://hummatch.me/contact`
