Developer Documentation
Building With the GuitarTheory API
This is a self-contained example — zero npm installs, zero build step, just a single HTML
file. It demonstrates four GuitarTheory REST API endpoints to generate a real-time music
theory quiz. Everything below explains exactly how each call works so you can adapt it.
Base URL:
https://www.guitartheory.com/api/v1 — all endpoints below are relative to this.
CORS is enabled, so requests work from any origin.
Full API reference and interactive docs at
guitartheory.com/docs.
Setup & Configuration
By default, BASE_URL points at https://www.guitartheory.com — the live
public API. It auto-detects localhost and any hostnames/IPs listed in
DEV_HOSTS, routing those requests to the local server instead.
To add a dev server, just append its IP or hostname to the DEV_HOSTS array.
// Add dev server IPs or hostnames here — they will use their own API.
const DEV_HOSTS = ['localhost', '127.0.0.1', '68.39.152.178'];
const BASE_URL =
(window.location.protocol === 'file:' || !window.location.hostname)
? 'https://guitartheory.com' // opened as a local file
: DEV_HOSTS.includes(window.location.hostname)
? window.location.origin // known dev server
: 'https://guitartheory.com'; // any other host → public API
// All API calls go through this one helper.
async function apiFetch(path) {
const res = await fetch(BASE_URL + path);
if (!res.ok) throw new Error(`API error: ${res.status} on ${path}`);
return res.json();
}
Endpoint 1 — Scale Notes
Returns all 7 notes in a scale, the interval pattern (semitone offsets from root),
display name, and a character description. Supports all 7 church modes plus
harmonic and melodic minor.
↳ Used for: "What is the Nth degree of X scale?" questions
// Ask: What is the 5th degree of G Mixolydian?
const root = 'G';
const mode = 'mixolydian';
const data = await apiFetch(`/api/v1/scales/${root}/${mode}`);
/* Full response:
{
"root": "G",
"mode": "mixolydian",
"displayName": "G Mixolydian",
"notes": ["G", "A", "B", "C", "D", "E", "F"],
"intervals": [0, 2, 4, 5, 7, 9, 10],
"character": "Bluesy, dominant, rock feel",
"notesWithOctaves": ["G4", "A4", "B4", "C5", "D5", "E5", "F5"]
} */
// notes[] is 0-indexed: notes[0] = root (1st degree),
// notes[4] = 5th degree, etc.
const degreeIndex = 4; // 5th degree
const correctNote = data.notes[degreeIndex]; // "D"
// Generate 3 wrong-answer notes from the chromatic scale
const ALL_NOTES = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
const wrongNotes = shuffle(ALL_NOTES.filter(n => n !== correctNote)).slice(0, 3);
Endpoint 2 — Interval Calculator
Calculates the interval between any two chromatic pitch classes. Returns the semitone
distance, the interval's full name, quality (major/minor/perfect/augmented/diminished),
and interval number (2nd, 5th, etc.).
↳ Used for: "What interval is between X and Y?" questions
// Ask: What interval is between C and G?
const data = await apiFetch('/api/v1/intervals/C/G');
/* Full response:
{
"note1": "C",
"note2": "G",
"semitones": 7,
"intervalName": "Perfect Fifth",
"quality": "perfect",
"number": 5
} */
const correct = data.intervalName; // "Perfect Fifth"
// Pool of all interval names for generating wrong answers
const ALL_INTERVALS = [
'Unison', 'Minor Second', 'Major Second', 'Minor Third', 'Major Third',
'Perfect Fourth', 'Tritone', 'Perfect Fifth', 'Minor Sixth',
'Major Sixth', 'Minor Seventh', 'Major Seventh', 'Octave'
];
const wrong = shuffle(ALL_INTERVALS.filter(n => n !== correct)).slice(0, 3);
Endpoint 3 — Key Analysis
Returns a full key analysis: all 7 scale notes, the relative minor (or major), and
all 7 diatonic chord names with their Roman numeral function. Quality is
major or minor.
↳ Used for: "What is the relative minor of X major?" questions
// Ask: What is the relative minor of D major?
const data = await apiFetch('/api/v1/keys/D/major');
/* Full response:
{
"key": "D",
"quality": "major",
"scale": ["D", "E", "F#", "G", "A", "B", "C#"],
"relativeMinor": "B",
"chords": {
"I": { "root": "D", "type": "major", "numeral": "I" },
"ii": { "root": "E", "type": "minor", "numeral": "ii" },
"iii": { "root": "F#", "type": "minor", "numeral": "iii" },
"IV": { "root": "G", "type": "major", "numeral": "IV" },
"V": { "root": "A", "type": "major", "numeral": "V" },
"vi": { "root": "B", "type": "minor", "numeral": "vi" },
"vii°":{ "root": "C#", "type": "diminished","numeral": "vii°"}
},
"commonProgressions": [ … ]
} */
const correct = data.relativeMinor + 'm'; // "Bm"
// Wrong answers: other minor keys (sampled from natural notes)
const NATURALS = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];
const wrong = shuffle(
NATURALS.filter(n => n !== data.relativeMinor)
).slice(0, 3).map(n => n + 'm');
Endpoint 4 — Modes Catalog
Returns all 7 church modes with interval patterns, display names, and
character descriptions. This endpoint is fetched once at game start and
cached — no repeated calls needed.
↳ Used for: "Which mode is described as '…'?" questions
// Fetch once, cache in a module-level variable
let modesCache = null;
async function getModes() {
if (!modesCache) {
const data = await apiFetch('/api/v1/modes');
modesCache = data.modes;
}
return modesCache;
}
/* Each mode object looks like:
{
"name": "lydian",
"displayName": "Lydian",
"intervals": [0, 2, 4, 6, 7, 9, 11],
"character": "Dreamy, ethereal, floating quality",
"relatedMode": "major"
} */
// Quiz: show mode.character → player picks mode.displayName
const modes = await getModes();
const target = modes[3]; // Lydian
const correct = target.displayName; // "Lydian"
const wrong = shuffle(
modes.filter(m => m.name !== target.name).map(m => m.displayName)
).slice(0, 3);
How the Game Loop Works
Questions are generated sequentially during the loading screen so all API calls
complete before play begins — no lag mid-game. Each generator function returns
a plain object with everything needed to render that question:
// Question object shape
{
type: 'scale' | 'interval' | 'keys' | 'modes',
question: 'What is the 5th note of …?', // shown to player
answers: ['D', 'F#', 'A', 'C'], // shuffled, 4 options
correct: 'D', // the right answer
apiCall: '/api/v1/scales/G/mixolydian', // displayed in callout
responseSnippet:'"notes": ["G","A","B","C","D","E","F"]',
explanation: 'G Mixolydian: G – A – B – C – D – E – F'
}
// Generation sequence (shuffled mix of all four types)
const generators = shuffle([
makeScaleQuestion, makeScaleQuestion, makeScaleQuestion,
makeIntervalQuestion, makeIntervalQuestion, makeIntervalQuestion,
makeKeysQuestion, makeKeysQuestion,
makeModesQuestion, makeModesQuestion,
]);
// Build all 10 questions before showing the quiz screen
const questions = [];
for (const gen of generators) {
questions.push(await gen()); // sequential so loading bar advances
}
Using This File in Your Project
This is a single self-contained HTML file — no build step, no dependencies.
Download it and drop it into any project or host it anywhere.
It calls the GuitarTheory API at https://www.guitartheory.com/api/v1 by default,
which has CORS enabled so it works from any origin.
// The file works out of the box — just open it in a browser.
// All API calls go to https://www.guitartheory.com/api/v1 by default.
// If self-hosting GuitarTheory on your own server, change this one line:
const BASE_URL = 'https://your-server.com'; // ← only change needed
Ideas for Extending This Example
The GuitarTheory API has five more endpoints not used in this game.
Each one opens up new game mechanics:
GET
/api/v1/chords/{root}/{type}
Quiz on chord spellings — "which notes are in Cmaj7?" — or render fretboard chord diagrams
GET
/api/v1/chord-types
Show the formula (1–♭3–5) and ask the player to name the chord type
GET
/api/v1/circle-of-fifths
Build an SVG circle and ask the player to click the correct key — uses the clockwise/counterClockwise arrays
GET
/api/v1/fretboard/scale/{root}/{mode}
Show a fretboard diagram with highlighted dots and ask the player to identify the scale