Ableton HTTP API
Protocol 0 turns Ableton Live 12 into something you can drive over local HTTP. Every action is a route — POST /api/action/<plugin>/<method> — so you can control Live from curl, a Stream Deck, an AutoHotkey script, or your own program. It's the exact same call a Protocol 0 keyboard shortcut makes under the hood.
Why an HTTP API for Ableton?
Ableton's own control surface scripts only react to MIDI, and Max for Live and the new Extensions SDK each have their own boundaries. None of them let an external program ask Live to do something. Protocol 0's remote script runs a small HTTP server inside Live, so anything that can send an HTTP request can trigger an action: select a track, load a device, read the set state. No MIDI loopback, no Max patch, no glue.
Where the API lives
There are two local servers, and they do different jobs:
| Server | Runs in | Address | Purpose |
|---|---|---|---|
| Script API | The remote script, inside Ableton | http://127.0.0.1:9000 * | The action API that drives Live |
| Agent | The background app (the keymapper) | http://127.0.0.1:9010 | The config web UI and keyboard hook |
* The script binds 9000 by default and falls back to an OS-chosen free port if it's taken. The actual URL is published in %APPDATA%\Protocol0\runtime.json (the script_url key), so tooling reads it from there rather than hardcoding the port.
The API only listens on 127.0.0.1 (localhost). It is never exposed to your network — Protocol 0 runs 100% on your machine.
Calling an action
Actions are POST routes. Parameters go in a JSON body, typed from the method signature. For example, to load a device onto the selected track:
curl -X POST http://127.0.0.1:9000/api/action/device/load_device \
-H "Content-Type: application/json" \
-d '{"name": "Wavetable"}'
Or to select a track by name:
curl -X POST http://127.0.0.1:9000/api/action/track/select \
-H "Content-Type: application/json" \
-d '{"name": "Drums"}'
Most actions are fire-and-forget: they return 200 OK once Live has scheduled the work. Actions that produce a value return it as JSON.
Reading the set state
A read-only GET returns a serialized snapshot of the current Live set — tracks, names, colors, and more:
curl http://127.0.0.1:9000/api/set/get_state
And a liveness check that also reports the running version:
curl http://127.0.0.1:9000/api/health
# {"ok": true, "version": "0.16.5"}
Built-in actions
Protocol 0 ships with a small, curated set of actions out of the box. They're the building blocks you bind to keyboard shortcuts — or call directly:
| Route | Body | What it does |
|---|---|---|
POST /api/action/track/select | {"name": "Drums"} | Select a track by name (use "master" for the master track). |
POST /api/action/device/load_device | {"name": "Wavetable"} | Load an instrument or audio effect onto the selected track. |
GET /api/set/get_state | — | Return the full serialized state of the current set. |
GET /api/health | — | Liveness check plus the running version. |
Adding your own action is a one-line @action decorator on a plugin method — see Extending Protocol 0.
OpenAPI spec & Swagger UI
The API is self-describing. The remote script generates a live OpenAPI 3.1 document from the current route registry, and serves an offline Swagger UI to explore it:
| Path | What |
|---|---|
GET /openapi.json | OpenAPI 3.1 spec, generated from the live routes and method docstrings. |
GET /docs | Swagger UI (vendored offline) to browse and try the actions. |
Because the spec is generated, you can feed /openapi.json to any OpenAPI client generator and get a typed SDK for free.
What can call it?
- A Protocol 0 keyboard shortcut — the built-in path, no setup.
- An Elgato Stream Deck button (a "Website" / multi-action HTTP request).
- An AutoHotkey script that POSTs to a route instead of replaying keystrokes.
- Your own program, in any language — it's just HTTP and JSON.