ReaServe communicates via JSON-RPC 2.0 over TCP with length-prefixed framing.
- Default port:
9876(configurable inreaserve.ini) - Default bind:
0.0.0.0
Each message is prefixed with a 4-byte big-endian uint32 indicating the payload length in bytes, followed by the UTF-8 JSON payload.
[4 bytes: length][N bytes: JSON payload]
{"jsonrpc": "2.0", "id": 1, "method": "ping", "params": {}}{"jsonrpc": "2.0", "id": 1, "result": {"pong": true, "version": "0.1.0"}}{"jsonrpc": "2.0", "id": 1, "error": {"code": -32601, "message": "Method not found"}}| Code | Meaning |
|---|---|
| -32700 | Parse error (malformed JSON) |
| -32600 | Invalid request (missing fields) |
| -32601 | Method not found |
| -32602 | Invalid params |
| -32603 | Internal error |
| -32000 | REAPER API error |
| -32001 | Lua execution error |
| -32002 | Timeout (main thread didn't process in time) |
Health check.
Params: none
Result:
{"pong": true, "version": "0.1.0"}Execute arbitrary Lua code in REAPER.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | yes | Lua source code |
Result:
{"success": true}Execute Lua code and return the output. The Lua code must call reaserve_output(json_string) to pass data back. Lua runtime errors are captured and returned as error responses.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | yes | Lua source code (must call reaserve_output() with a JSON string) |
Result: The parsed JSON from reaserve_output(). If the output is not valid JSON, it is returned as {"raw": "<output>"}.
Errors:
-32603— Lua runtime error (message includes the Lua error)-32603— Script did not callreaserve_output()
Example:
{
"jsonrpc": "2.0", "id": 1,
"method": "lua.execute_and_read",
"params": {
"code": "local info = {bpm = 120}\nreaserve_output(reaper.json_encode and reaper.json_encode(info) or '{\"bpm\": 120}')"
}
}Client implementation notes:
The code value is a JSON string that is decoded and written to a .lua file verbatim. This means:
- Newlines must be JSON-escaped. Literal newlines are invalid inside JSON strings. Use
\nin the JSON value, or rely on your language's JSON encoder to handle this automatically (most do). - Double quotes inside Lua code must be JSON-escaped. For example,
reaper.ShowConsoleMsg("hello")must be sent asreaper.ShowConsoleMsg(\"hello\")in the raw JSON. Again, a JSON encoder handles this — just pass the Lua code as a native string and let the encoder do the escaping. - Prefer Lua single quotes or
[[ ]]long brackets to avoid fighting with JSON double-quote escaping.reaper.ShowConsoleMsg('hello')is easier to read and construct than the double-escaped equivalent. lua.execute_and_readwraps your code inpcall(function() ... end). This is transparent — your code runs in a new scope but has full access to all globals (reaper, etc.). The only visible effect is thatreaserve_outputand the names__ok/__errare defined in the outer scope. Avoid shadowing these.
Get current project state.
Params: none
Result:
{
"bpm": 120.0,
"time_sig_num": 4,
"time_sig_denom": 4,
"track_count": 3,
"cursor_position": 5.2,
"play_state": 0,
"project_length": 120.0,
"tracks": [
{
"index": 0,
"name": "Drums",
"volume_db": -3.0,
"pan": 0.0,
"mute": false,
"solo": false,
"record_arm": false,
"fx_count": 2,
"item_count": 4
}
]
}Get transport state.
Params: none
Result:
{
"play_state": 1,
"state_name": "playing",
"cursor_position": 12.5,
"is_playing": true,
"is_paused": false,
"is_recording": false
}Control transport.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
action |
string | yes | play, stop, pause, or record |
Result:
{"success": true, "action": "play"}Move the edit cursor.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
position |
number | yes | Time in seconds |
moveview |
boolean | no | Move arrange view (default: true) |
seekplay |
boolean | no | Seek playback (default: true) |
Result:
{"success": true, "position": 10.0}Add a new track.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | no | Track name |
index |
integer | no | Insert position (default: end) |
Result:
{"success": true, "index": 3, "track_count": 4}Remove a track.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
index |
integer | yes | Track index |
Result:
{"success": true, "track_count": 2}Set a track property.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
index |
integer | yes | Track index |
property |
string | yes | One of: name, volume_db, pan, mute, solo, record_arm |
value |
any | yes | New value (type depends on property) |
Result:
{"success": true}Get all selected media items.
Params: none
Result:
{
"count": 1,
"items": [
{
"index": 0,
"position": 2.0,
"length": 4.0,
"mute": false,
"selected": true,
"take_name": "audio.wav",
"source_type": "WAVE",
"track_index": 0
}
]
}List all items, optionally filtered by track.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | no | Filter to specific track |
Result:
{
"count": 5,
"items": [...]
}Move a media item.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
item_index |
integer | yes | Item index within track |
position |
number | yes | New position in seconds |
Resize a media item.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
item_index |
integer | yes | Item index within track |
length |
number | yes | New length in seconds |
Split a media item.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
item_index |
integer | yes | Item index within track |
position |
number | yes | Split position in seconds |
Delete a media item.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
item_index |
integer | yes | Item index within track |
Get FX parameters.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
fx_index |
integer | yes | FX index on track |
Result:
{
"fx_name": "VST: ReaEQ (Cockos)",
"enabled": true,
"param_count": 16,
"parameters": [
{
"index": 0,
"name": "Band 1 Frequency",
"value": 0.5,
"min": 0.0,
"max": 1.0,
"formatted": "1000 Hz"
}
]
}Add FX to a track.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
fx_name |
string | yes | FX name (e.g. "ReaEQ") |
position |
integer | no | FX chain position (default: -1 = end) |
Result:
{"success": true, "fx_index": 0}Remove FX from a track.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
fx_index |
integer | yes | FX index |
Set an FX parameter value.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
fx_index |
integer | yes | FX index |
param_index |
integer | yes | Parameter index |
value |
number | yes | New value (normalized 0-1) |
Enable or disable (bypass) an FX.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
fx_index |
integer | yes | FX index |
Get MIDI notes from an item.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
item_index |
integer | yes | Item index |
Result:
{
"note_count": 4,
"cc_count": 0,
"notes": [
{
"index": 0,
"pitch": 60,
"velocity": 100,
"channel": 0,
"start_ppq": 0.0,
"end_ppq": 960.0,
"start_time": 0.0,
"end_time": 1.0,
"start_qn": 0.0,
"end_qn": 1.0,
"selected": false,
"muted": false
}
]
}Insert MIDI notes. Creates a new MIDI item if item_index is not provided.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
item_index |
integer | no | Existing item (creates new if omitted) |
start_time |
number | no | Start time for new item (default: 0) |
end_time |
number | no | End time for new item (default: start + 4) |
notes |
array | yes | Array of note objects |
Each note object:
| Field | Type | Required | Description |
|---|---|---|---|
pitch |
integer | no | MIDI note number (default: 60) |
velocity |
integer | no | Velocity (default: 100) |
channel |
integer | no | MIDI channel (default: 0) |
start_ppq/end_ppq |
number | * | Position in PPQ ticks |
start_qn/end_qn |
number | * | Position in quarter notes |
start_time/end_time |
number | * | Position in seconds |
*One pair of start/end is required (ppq, qn, or time).
Result:
{"success": true, "notes_inserted": 4}List all markers and regions.
Params: none
Result:
{
"marker_count": 3,
"region_count": 1,
"markers": [
{"index": 1, "position": 0.0, "name": "Intro"},
{"index": 2, "position": 30.0, "name": "Verse"}
],
"regions": [
{"index": 1, "position": 0.0, "end_position": 30.0, "name": "Section A"}
]
}Add a marker or region.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
position |
number | yes | Position in seconds |
name |
string | no | Marker name |
index |
integer | no | Desired index (-1 = auto) |
is_region |
boolean | no | Create region (default: false) |
end_position |
number | no | Region end position |
Remove a marker or region.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
index |
integer | yes | Marker/region index |
is_region |
boolean | no | Remove region (default: false) |
List sends/receives for a track.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
category |
integer | no | 0=sends, 1=receives, -1=hw outputs (default: 0) |
Result:
{
"track_index": 0,
"category": 0,
"count": 1,
"sends": [
{
"index": 0,
"volume": 1.0,
"pan": 0.0,
"mute": false,
"dest_channel": 0,
"src_channel": 0
}
]
}Create a send between tracks.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
src_track |
integer | yes | Source track index |
dest_track |
integer | yes | Destination track index |
volume |
number | no | Send volume |
pan |
number | no | Send pan |
Result:
{"success": true, "send_index": 0}Remove a send.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
send_index |
integer | yes | Send index |
category |
integer | no | Category (default: 0) |
List envelope automation points.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
envelope_name |
string | yes | Envelope name (e.g. "Volume", "Pan") |
Result:
{
"envelope_name": "Volume",
"point_count": 3,
"points": [
{"index": 0, "time": 0.0, "value": 1.0, "shape": 0, "tension": 0.0, "selected": false}
]
}Add an automation point.
Params:
| Field | Type | Required | Description |
|---|---|---|---|
track_index |
integer | yes | Track index |
envelope_name |
string | yes | Envelope name |
time |
number | yes | Time in seconds |
value |
number | yes | Envelope value |
shape |
integer | no | Point shape (default: 0 = linear) |
tension |
number | no | Tension (default: 0.0) |
Result:
{"success": true, "point_index": 0}