Reference

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:

ServerRuns inAddressPurpose
Script APIThe remote script, inside Abletonhttp://127.0.0.1:9000 *The action API that drives Live
AgentThe background app (the keymapper)http://127.0.0.1:9010The 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:

RouteBodyWhat 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_stateReturn the full serialized state of the current set.
GET /api/healthLiveness 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:

PathWhat
GET /openapi.jsonOpenAPI 3.1 spec, generated from the live routes and method docstrings.
GET /docsSwagger 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?