REST API · OpenAPI 3.1 · MCP server
Developer API
Turn files, links and text into chords and lyrics, then read and fill your songbook from a script or an assistant.
- Free tier
- Same engine as the app
- Official MCP server
What the API does
Each capability is unlocked by a scope you tick when creating your key.
Conversion
Audio, PDF, images, text or a link to songbook, PDF, MIDI, MusicXML and more.
Private songbook
List, read, create, edit and organize your songs and playlists.
Public profiles
Read only: profiles, published songs, followers. No soundtrack.
Stem separation
A conversion (output=stems) splits vocals from accompaniment; the /stem-tool tool splits into two or four stems. With an API key, both require a Premium account.
Audio queue
Chord and lyric analysis in the same queue as the app.
AI music detection
A generation hint for a file, a Spotify link, a direct audio link or an ISRC.
Limits, quotas and privacy
AI-generated music is increasingly common. Jam Jam helps you look for signs of generation: paste a link or upload a file for an indicative result.
100 MB max · 10 min max · Spotify, direct audio link or ISRC. YouTube is not supported. Spotify links may be analysed from a preview only.
One queued or running file per account. Premium accounts have priority in the queue.
Guest: 2 scans/day and 5/month. Free account: 5/day and 50/month. Premium: 30/day and 300/month. Shared across website, app and API; failed scans are not charged. Resets at midnight UTC and on the first of each month UTC.
Audio is sent to our detection provider SH Labs for analysis. It states that audio is not retained or used to train models. If unavailable, a file may be analyzed locally when fallback is available. Our temporary files are deleted after processing, failure or cancellation. Your account keeps the filename or link, date, status and result for 90 days. Guest results remain available for 24 h. Guest limits use a token and a pseudonymized network identifier, without retaining the plain IP address.
This index is neither a probability nor proof. A low index does not guarantee human origin.
Explore the toolSupported formats
The full, current list, with exact limits and what this server actually serves, is always at GET /formats. In short:
Input formats
- Audio and video files
- PDF: chords, lyrics, sheet music, tab, scanned songbook
- Images: chords, lyrics, sheet music, tab
- Plain text, ChordPro, OnSong
- Links and web search (page-link, web-search)
- MusicXML, MIDI
- JamSong, mixed .zip, songbook (pivot)
Output formats
- Songbook (JSON pivot, always available)
- PDF: chords, lyrics, sheet music, tab, grid
- PNG, HTML, plain text, ChordPro
- chords-lab, chords-csv, key and BPM
- MusicXML, MIDI (Premium)
- Synced lyrics: .lrc, .srt
- Karaoke video (.mp4), backing audio, JamSong
Get started in four steps
Conversion is asynchronous: submit, track, fetch.
-
Create a key
Settings › API keys.
Manage my API keysjj_live_prefix, shown once, 5 keys per account, revocable. -
Submit
A file, a URL or text, with the output format you want.
POST /jobs -
Track
Poll while honoring
Retry-After, or open a Server-Sent Events stream.GET /jobs/{id}GET /jobs/{id}/events -
Fetch
The result stays available for 24 hours, then 410 Gone.
GET /jobs/{id}/result
Examples
Complete calls, ready to copy as is.
List the formats this server servescurl
curl https://jam-jam.org/api/v1/formatsConvert a file to PDFcurl
curl -X POST https://jam-jam.org/api/v1/jobs \
-H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
-F [email protected] \
-F inputFormat=pdf-songbook \
-F output=pdf-songbookConvert a URL to a songbookcurl
curl -X POST https://jam-jam.org/api/v1/jobs \
-H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/tabs/amazing-grace", "output": "songbook"}'Follow progress (SSE or polling)curl
# Server-Sent Events
curl -N -H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
https://jam-jam.org/api/v1/jobs/jb_123/events
# Polling
curl -H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
https://jam-jam.org/api/v1/jobs/jb_123Download the resultcurl
curl -H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
-OJ https://jam-jam.org/api/v1/jobs/jb_123/resultPython (requests)python
import time
import requests
API = "https://jam-jam.org/api/v1"
HEADERS = {"Authorization": "Bearer jj_live_xxxxxxxxxxxxxxxx"}
# 1. Discover formats
formats = requests.get(f"{API}/formats").json()
# 2. Submit a conversion
resp = requests.post(
f"{API}/jobs",
headers=HEADERS,
json={"url": "https://example.com/tabs/amazing-grace", "output": "songbook"},
)
resp.raise_for_status()
job = resp.json()
# 3. Poll until done (or use GET /jobs/{id}/events for SSE)
while job["phase"] not in ("done", "failed", "cancelled"):
time.sleep(job.get("etaS", 2))
job = requests.get(f"{API}/jobs/{job['id']}", headers=HEADERS).json()
# 4. Fetch the result
if job["phase"] == "done":
songbook = requests.get(f"{API}/jobs/{job['id']}/result/songbook", headers=HEADERS).json()
print(songbook["songs"][0]["title"])
else:
print("failed:", job.get("problem"))Analyze a track with AI music detectioncurl
# Availability and remaining quota (no key needed)
curl https://jam-jam.org/api/v1/ai-music/availability
# Analyze a file
curl -X POST https://jam-jam.org/api/v1/ai-music/jobs \
-H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
-F "[email protected]"
# Analyze a Spotify link
curl -X POST https://jam-jam.org/api/v1/ai-music/jobs \
-H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url":"https://open.spotify.com/track/2JUDGXTQYGQZrVVUgq40Ke"}'
# History, current analysis, one analysis
curl -H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
https://jam-jam.org/api/v1/ai-music/history
curl -H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
https://jam-jam.org/api/v1/ai-music/jobs
curl -H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
https://jam-jam.org/api/v1/ai-music/jobs/JOB_ID
# Cancel
curl -X DELETE -H "Authorization: Bearer jj_live_xxxxxxxxxxxxxxxx" \
https://jam-jam.org/api/v1/ai-music/jobs/JOB_IDCode examples
Ready-to-run examples in curl, JavaScript and Python, open source under the MIT licence:
Assistants and MCP
An assistant reads the contract and builds its own calls. The official MCP server gives it 42 ready-made tools.
For AI agents
Read GET /openapi.json first: it documents the recommended call sequence (discover formats, submit, track, fetch), authentication and quotas in an x-agent-guide block meant to be parsed by a model. llms.txt on this site lists each conversion capability as its own entry.
MCP server
Key read from JAM_JAM_API_KEY: only the tools its scopes allow appear. It follows no one, likes nothing and publishes nothing on its own.
In detail
An official Model Context Protocol server exposes the API to an assistant as 42 tools prefixed jj_: file and text conversion, reading and organising your private notebook, reading public profiles, stem separation, audio analysis and the job queue, AI music detection and Mastering. It reads your API key from the JAM_JAM_API_KEY environment variable and only shows the tools that the scopes of that key allow. It handles polling, quota errors and file results for you, so an assistant like Claude Desktop, Claude Code or Cursor can convert a file or organise your notebook without you writing any HTTP code. It never follows anyone, likes anything or publishes a song on its own.
npx -y @jam-jam/convert-mcpPackage page on npm: npmjs.com/package/@jam-jam/convert-mcp
{
"mcpServers": {
"jam-jam": {
"command": "npx",
"args": ["-y", "@jam-jam/convert-mcp"],
"env": {
"JAM_JAM_API_KEY": "jj_live_xxxxxxxxxxxxxxxx"
}
}
}
}Tools and required scopes 42
formats, files, text and job status.
jj_list_formatsno scopejj_convert_fileconvert:writejj_convert_textconvert:writejj_get_jobconvert:read
what the key may do and how much is left.
jj_check_usage
songs and playlists.
jj_list_songsjj_get_songjj_list_playlistsjj_get_playlist
create, update and delete songs and playlists.
jj_create_songjj_update_songjj_delete_songjj_create_playlistjj_update_playlistjj_delete_playlist
profile cards, published songs and playlists, followers and following.
jj_get_profilejj_list_profile_songsjj_list_profile_playlistsjj_list_followersjj_list_following
capabilities, jobs and files.
jj_stems_capabilitiesconvert:readjj_stems_separatestems:writejj_stems_get_jobconvert:readjj_stems_list_jobsconvert:readjj_stems_get_fileconvert:readjj_stems_cancel_jobstems:write
analyse a file, then list, read and cancel jobs.
jj_audio_analyzeaudio:writejj_queue_listqueue:readjj_queue_get_jobqueue:readjj_queue_cancel_jobaudio:write
availability, analysis, history and jobs.
jj_ai_music_availabilityqueue:readjj_ai_music_analyzeaudio:writejj_ai_music_currentqueue:readjj_ai_music_get_jobqueue:readjj_ai_music_historyqueue:readjj_ai_music_cancel_jobaudio:write
capabilities, presets, render, job status and cancellation.
jj_mastering_capabilitiesno scopejj_list_mastering_presetsmastering:readjj_create_mastering_presetmastering:writejj_master_audiomastering:writejj_mastering_get_jobmastering:readjj_mastering_cancel_jobmastering:write
Endpoint reference
Every route served, by family, with its scope and quota. The full contract is authoritative.
- Conversion (jobs) 6
- Formats 1
- Usage & quotas 1
- Notebook, reading 4
- Notebook, writing 8
- Social, reading only 5
- Audio queue & stems 4
- Stem separation 6
- Mastering 8
- AI music detection 7
- Health & specification 2
Conversion (jobs) 6
| Method | Path | Scope | Quota |
|---|---|---|---|
| POST | /jobsSubmit a conversion: a file (multipart/form-data), a URL or raw text/ChordPro (application/json). output=stems also needs stems:write and a Premium API key, with its own quota (200/UTC day). | convert:write | quota: conversion |
| GET | /jobs/{id}Job status (phase, percent, steps). Poll and respect the Retry-After header. | convert:read | quota: none |
| DELETE | /jobs/{id}Cancel a job and erase its files; refunds the quota only if it was still queued. | convert:write | quota: none |
| GET | /jobs/{id}/eventsServer-Sent Events alternative to polling: state, done, error and keep-alive ping events. | convert:read | quota: none |
| GET | /jobs/{id}/resultDownload the main artifact (or a specific one via ?artifact=). Available 24 hours after the job was created. | convert:read | quota: none |
| GET | /jobs/{id}/result/songbookThe canonical songbook JSON pivot (chords, lyrics, structure), always available once the job is done. | convert:read | quota: none |
Formats 1
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /formatsRegistry of the input/output pairs this server actually serves, with limits (maxBytes, maxPages, maxDurationS). | public (no key needed) | quota: none |
Usage & quotas 1
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /me/usageYour quota balance (conversion, read, write, stems) and the scopes your identity can actually exercise, in one call. | convert:read | quota: none |
Notebook, reading 4
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /me/songsList the songs in your private notebook, paginated by opaque cursor; use updatedSince for incremental export. | carnet:read | quota: read |
| GET | /me/songs/{songId}One full song from your notebook, chords, lyrics and structure included. | carnet:read | quota: read |
| GET | /me/playlistsList the playlists in your notebook, flat and multi-membership, same pagination as songs. | carnet:read | quota: read |
| GET | /me/playlists/{playlistId}One playlist and its songs, in order, in summary form. | carnet:read | quota: read |
Notebook, writing 8
| Method | Path | Scope | Quota |
|---|---|---|---|
| POST | /me/songsAdd a song to your notebook, the same pivot payload a conversion returns. Set Idempotency-Key to avoid duplicates. | carnet:write | quota: write |
| PUT | /me/songs/{songId}Replace a song entirely (declarative); creates it under that id if it does not exist yet. | carnet:write | quota: write |
| PATCH | /me/songs/{songId}Update only the fields you send (key, capo, bpm, playlistIds...); also publishes or unpublishes the song to your profile. | carnet:write | quota: write |
| DELETE | /me/songs/{songId}Remove a song from your notebook; soft, idempotent, and it leaves every playlist too. | carnet:write | quota: write |
| POST | /me/playlistsCreate a playlist; songIds is the ordered list of songs it contains, kept exactly as sent. | carnet:write | quota: write |
| PUT | /me/playlists/{playlistId}Replace a playlist entirely (declarative); songIds is required. | carnet:write | quota: write |
| PATCH | /me/playlists/{playlistId}Rename, change the cover emoji or fully reorder a playlist's songs. | carnet:write | quota: write |
| DELETE | /me/playlists/{playlistId}Delete the playlist itself; its songs stay in your notebook and in their other playlists. | carnet:write | quota: write |
Social, reading only 5
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /users/{handle}Public profile header of an account by handle; a private account you do not follow returns a closed card (no bio, no counts). | social:read | quota: read |
| GET | /users/{handle}/songsSongs an account has published on its profile; audioPlayable is only true when you follow each other mutually. | social:read | quota: read |
| GET | /users/{handle}/playlistsPlaylists an account has published; songCount only counts what you can actually see. | social:read | quota: read |
| GET | /me/followersAccounts that follow you; status=accepted (default) or requested. | social:read | quota: read |
| GET | /me/followingAccounts you follow; status=requested lists the private-account requests still pending. | social:read | quota: read |
Audio queue & stems 4
| Method | Path | Scope | Quota |
|---|---|---|---|
| POST | /audioQueue automatic chord and lyrics analysis, then alignment, for a song already in your notebook. Same queue as the app; songId must be yours. | audio:write | quota: none |
| GET | /queueYour account's audio processing queue: active, queued (with rank) and the last 7 days done. | queue:read | quota: none |
| GET | /queue/{id}One audio queue job, yours only; same indistinct 404 for an unknown or someone else's job. | queue:read | quota: none |
| DELETE | /queue/{id}Cancel one of your audio queue jobs; refunds only if the analysis had not completed yet. | audio:write | quota: none |
Stem separation 6
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /stem-tool/capabilitiesCheck availability, limits, models and the caller’s quota for stem separation. | convert:read | quota: none |
| GET | /stem-tool/jobsList the caller’s private stem-separation jobs, with an optional pagination cursor. | convert:read | quota: none |
| POST | /stem-tool/jobsUpload an audio file and start separating it into two or four stems. API keys require Premium. | stems:write | quota: stems |
| GET | /stem-tool/jobs/{id}Read the status, progress and available files of one of the caller’s jobs. | convert:read | quota: none |
| DELETE | /stem-tool/jobs/{id}Cancel one of the caller’s stem-separation jobs. | stems:write | quota: none |
| GET | /stem-tool/jobs/{id}/files/{name}Get a short-lived signed download URL for an MP3 stem or ZIP archive. | convert:read | quota: none |
With an API key, every one of these routes requires a Premium account; otherwise the response is a 403 (api-premium-required). The caller’s limits are in GET /stem-tool/capabilities.
Mastering 8
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /mastering/capabilitiesLimits, setting ranges, loudness targets, built-in presets and render right. | public (no key needed) | quota: none |
| GET | /mastering/presetsList your mastering presets. | mastering:read | quota: none |
| POST | /mastering/presetsCreate a mastering preset (Idempotency-Key required). | mastering:write | quota: none |
| DELETE | /mastering/presets/{id}Delete one of your mastering presets. | mastering:write | quota: none |
| POST | /mastering/jobsUpload audio and start a mastering render with a preset or settings. | mastering:write | quota: mastering (3/week free, unlimited Premium) |
| GET | /mastering/jobs/{id}Get the status of a mastering job. | mastering:read | quota: none |
| DELETE | /mastering/jobs/{id}Cancel a mastering job. | mastering:write | quota: none |
| GET | /mastering/jobs/{id}/resultDownload the mastered WAV. | mastering:read | quota: none |
AI music detection 7 + 1 internal
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /ai-music/availabilityTool availability, accepted formats and the remaining quota of the account or visitor. | public (no key needed) | quota: none |
| POST | /ai-music/jobsSubmit an audio file, a Spotify link, a direct audio link or an ISRC. One unfinished job per account; YouTube is not supported. | audio:write | quota: AI detection |
| GET | /ai-music/jobsFind your current or most recent analysis. | queue:read | quota: none |
| GET | /ai-music/jobs/{id}Follow an analysis and read its report. | queue:read | quota: none |
| DELETE | /ai-music/jobs/{id}Cancel an analysis and delete its temporary files. | audio:write | quota: none |
| GET | /ai-music/historyPrivate history of the last 90 days, in pages of 30; account required, no audio kept. | queue:read | quota: none |
| DELETE | /ai-music/history/{id}Delete a scan from your history; the quota of a successful analysis is not refunded. | audio:write | quota: none |
| GET | /ai-music/source/{token}/{filename}Temporary address reserved for the detection provider, valid for 180 seconds at most: no client calls it. | internal | quota: none |
Health & specification 2
| Method | Path | Scope | Quota |
|---|---|---|---|
| GET | /healthService status and readiness per engine (OMR, audio, video...); no authentication required. | public (no key needed) | quota: none |
| GET | /openapi.jsonThis contract, as machine-readable JSON. | public (no key needed) | quota: none |
Full machine-readable contract, always in sync with this table:
https://jam-jam.org/api/v1/openapi.json OpenAPI contract Quotas and limits
The exact balance is in GET /me/usage and in the X-Quota-* headers of each response.
Conversion
- Free account
- 6 / week
- Premium
- 500 / month
- No key, no session
- 3 / 24 h
Same counter as songbook export in the app.
Reads and writes
| per UTC day | Free account | Premium |
|---|---|---|
| Reads (songbook, profiles) | 2,000 | 20,000 |
| Writes (songbook) | 200 | 5,000 |
X-Read-Quota-* · X-Write-Quota-*
Stems from a conversion
POST /jobs · output=stems Premium API key required: without Premium, the response is a 403 (premium-required).
- Premium
- 200 per UTC day
By calling these routes you confirm you hold the rights to the audio you send.
In detail
POST /jobswithoutput=stemsreturns a.zip:vocals,accompanimentandmanifest.json.- Required scopes:
stems:writeandconvert:write. - A separate counter from conversions, counted per UTC day (not a rolling 24 hours).
- Not to be confused with the Stem separation tool (
/stem-tool/*): an API key there requires a Premium account, with its own limits (GET /stem-tool/capabilities).
Getting an API key
Create a free Jam Jam account, then open Settings, API keys in the app (mobile or web) and create a key. It starts with jj_live_ and is shown once: copy it right away. Up to 5 keys per account, revocable at any time.
Errors
Every error, on every route, is an application/problem+json object (RFC 9457) with a stable code field a client can branch on: quota-exhausted, rate-limited, unsupported-pair, not-found... The full catalogue is in the OpenAPI schema (components.schemas.Problem).
Retention
Uploaded files and generated results are deleted 24 hours after the job is created. Nothing is kept longer, including failed jobs. Fetching a result past that window returns 410 Gone.
Open-source credits
This API stands on real open-source engines. Used honestly, credited by name:
- MuseScore 4
GPL-3.0Notation import and rendering, sheet music PDF - Audiveris
AGPL-3.0Optical music recognition (scanned sheet music) - Tesseract OCR
Apache-2.0Text recognition in scanned pages and photos - faster-whisper
MITSpeech-to-text for lyrics from audio - Basic Pitch
Apache-2.0Note and melody detection from audio - FluidSynth
LGPL-2.1Backing-track rendering from MIDI (SoundFont synthesis) - FFmpeg
LGPL-2.1 / GPL-2.0Audio and video encoding, format conversion - Chromium
BSD-3-ClauseHeadless rendering of sheet music and chord sheets to PDF
Models and data
Speaker detection (Studio): WeSpeaker ResNet34-LM voice embedding model, WeNet project (github.com/wenet-e2e/wespeaker), trained on VoxCeleb (VGG, University of Oxford), licence CC BY 4.0 (creativecommons.org/licenses/by/4.0/). Modified by Jam Jam: weights converted to half precision.