Five POST endpoints on one base URL. Every body is JSON, every call carries your key as a bearer token, and every response is deterministic: the same input returns the same output, byte for byte.
Updated 2026-10-02
Basics
Base URL
https://chords.thiri.ai
Auth
Authorization: Bearer sk_live_… on every request. Get a key.
Content type
Content-Type: application/json. Bodies over 64 KB are rejected with 413.
Method
All theory endpoints are POST. GET /v2/account reads your usage.
Chord symbols
Standard jazz notation: Cmaj7, Dm7b5, G7#9, F#m11, Bb13, slash chords like C/E. Flats are b, sharps #.
Keys
A tonic such as C, Bb, F#, or a minor key like Em or E minor. Modes are expressed through their parent key: for B♭ Lydian pass F.
CORS
An allowlist of THIRI origins. A browser app on another domain is blocked by CORS, and a key in client-side code is visible to everyone anyway: put a small server-side proxy in front of the API (that is what this site's instruments do).
Quota headers
Every /v2 response reports your monthly position. A successful call counts; a 4xx does not.
An instrument-ready voicing. Pass the previous chord's notes and THIRI minimises motion between them and reports a voice-leading score (lower is smoother).
Field
Type
Notes
chord
string, required
style
string
rootless (default), bill_evans, shell, triad, pad, guide-tones, guide-tone-1, guide-tone-2, both-guide-tones, drop-2, drop-3 (drop2 and drop3 are accepted too). An unknown style falls back to the default without an error, so check the style echoed in the response.
keyContext
string
Key for colour choices and avoid notes.
octave
integer
Register of the lowest voice. Default 3.
previousVoicing
object
{ "notes": ["G3","Bb3","D4","F4"] } or { "midi": [55,58,62,65] }. Anything else is a 400.
Alternatives for a whole progression. Each alternative names its technique, lists exactly what changed, and explains why it works, so an agent can show its reasoning.
Field
Type
Notes
progression
string[], required
Chord symbols in order. bars is accepted as an alias.
key
string
Strongly recommended; borrowed chords and secondary dominants need it.
technique
string
Restrict to one: tritone_sub, ii_v_insertion, modal_interchange, secondary_dominant, chain_of_dominants, diminished_passing, backdoor, coltrane_changes. Omit for all eight.
A plain-English direction becomes a four-lane band arrangement (harmony, pattern, bass, drums; ticks at 480 ppq) and a multi-track MIDI file. The engine is pure JavaScript; your side plays or renders it (the Conductor instrument uses Csound in the browser).
Field
Type
Notes
prompt
string, required
Key, feel, tempo words, instruments and length are all read from the text.
durationSec
number
Override the interpreted length.
request
{"prompt": "4-bar swung loop in F for piano, bass and drums"}
// Save the MIDI that /v2/conduct returnsimport { writeFileSync } from "node:fs";const { midiBase64 } = await res.json();writeFileSync("loop.mid", Buffer.from(midiBase64, "base64"));
GET /v2/account
Your key's tier, limits and the last seven days of calls. The usage dashboard is a view of this response.
THIRI computes from pitch-class sets and a fixed grid of voicing and reharmonization rules. There is no sampling and no model in the loop, so a request is reproducible and cacheable.
If you build an evaluation around THIRI, you can snapshot responses as golden files; they will not drift between calls or between versions unless the changelog says the grid changed.
Also on the worker
POST /v2/compose and POST /v2/render (Csound rendering through a container service) and the /v2/video/* jobs exist for the instruments and the score-to-picture work. They are not yet stable for third parties; ask before building on them.