Actions API Reference
actions.proto, service ActionsService. This is the recommended default surface for integrations — see Overview & Setup if you haven't read that yet (connection details, auth, and the h2c cleartext requirement all apply here).
ActionsService mirrors Aura Mixer's internal Action Registry — the same catalog Hotkeys and Automation rules bind to. Every action is addressed by a stable, namespaced string ID (e.g. mixer.setMuted), never by a raw index, so your integration doesn't need to know anything about how channels/buses are laid out internally.
Target IDs
Actions that operate on a specific entity (a channel, bus, group, or the main bus) take a project-local ID — an opaque string like ch_53f465c2, stable for the lifetime of that entity but not predictable or guessable. Get real IDs from StreamState (which pairs every ID with its current display name) — don't hardcode them.
If an ID doesn't resolve to anything (the entity was deleted since you last looked it up), InvokeAction returns ok: false rather than throwing — it never guesses.
RPCs
ListActions
rpc ListActions(google.protobuf.Empty) returns (ActionList);
message ActionDefinition {
string id = 1; // e.g. "mixer.setMuted"
string display_name = 2; // e.g. "Mute / Unmute"
string category = 3; // e.g. "Mixer", "Routing", "Scenes", "Engine"
bool requires_target = 4; // needs target_id to do anything
string target_kind = 5; // "mixable" | "bus" | "channel" — see below
bool requires_secondary_target = 6; // needs secondary_target_id too (two-entity actions)
bool uses_value = 7; // reads an absolute numeric value
bool uses_delta = 8; // reads a relative step
bool supports_momentary = 9; // has a natural on/off (fire true on press, false on release)
}
message ActionList { repeated ActionDefinition actions = 1; }
Call this once at startup to build your own picker — don't hardcode the action catalog, it can grow. target_kind tells you what a target_id for that action must reference: "mixable" (any channel, group, output bus, or the main bus — anything with mute/solo/fader), "bus" (output buses and the main bus only), or "channel" (input channels only) — plus four narrower kinds for type-specific transport, each restricted to exactly that channel/bus type so a picker can't offer, say, a microphone channel for a Player action: "playerChannel", "generatorChannel", "soundboardChannel", and "recorderBus" (which, unlike plain "bus", never includes the main bus — it can never be a Recorder).
InvokeAction
rpc InvokeAction(InvokeActionRequest) returns (InvokeActionResponse);
message InvokeActionRequest {
string action_id = 1;
string target_id = 2; // required if the action's requires_target is true
string secondary_target_id = 3; // required if requires_secondary_target is true
optional float value = 4; // for actions with uses_value
optional float delta = 5; // for actions with uses_delta
optional bool flag = 6; // explicit on/off; omit to toggle (for actions that support it)
}
message InvokeActionResponse {
bool ok = 1;
string error = 2; // human-readable, empty when ok
}
InvokeActionResponse.ok is your real success signal — check it. ok: false happens for an unknown action_id, or a requires_target action called without a target_id; it is not a gRPC-level error, so a try/catch around the call alone won't catch it.
flag matters for actions that supports_momentary: pass flag: true on button-down and flag: false on button-up for a press-and-hold behavior (e.g. push-to-mute); omit flag entirely for a simple toggle-on-press.
StreamState
rpc StreamState(google.protobuf.Empty) returns (stream MixerStateSnapshot);
message MixerEntityState {
string id = 1;
string name = 2; // current display name — cache this for your UI, don't re-resolve per-call
string kind = 3; // "channel" | "group" | "output" | "mainBus"
bool muted = 4;
bool soloed = 5;
float fader_db = 6;
}
message MixerStateSnapshot { repeated MixerEntityState entities = 1; }
Opens a long-lived stream. You get one snapshot immediately on connect (covering every channel/group/output/main-bus currently in the project), then a fresh full snapshot every time anything changes — not a delta. This is the right way to:
- Discover valid
target_ids (paired with their current names) instead of guessing. - Drive a button icon's mute/solo/fader-level indicator live.
If you only care about specific entities, just filter the snapshot client-side — the list is small (typically well under a hundred entities) and this keeps the protocol simple in both directions.
Built-in action catalog
As of this writing, ListActions returns these 24 actions (call it yourself for the authoritative, current list — this table is a snapshot):
| ID | Display name | Category | Target | Value/Delta | Momentary |
|---|---|---|---|---|---|
mixer.setMuted | Mute / Unmute | Mixer | mixable | — | ✓ |
mixer.setSoloed | Solo / Unsolo | Mixer | mixable | — | ✓ |
mixer.setFaderDb | Set Fader (absolute) | Mixer | mixable | value (dB) | |
mixer.adjustFaderDb | Adjust Fader (relative) | Mixer | mixable | delta (dB) | |
mixer.clearAllSolo | Clear All Solo | Mixer | — | — | |
player.play | Player: Play | Mixer | playerChannel | — | |
player.pause | Player: Pause | Mixer | playerChannel | — | |
player.stop | Player: Stop | Mixer | playerChannel | — | |
player.togglePlayPause | Player: Play / Pause | Mixer | playerChannel | — | |
player.next | Player: Next Track | Mixer | playerChannel | — | |
player.previous | Player: Previous Track | Mixer | playerChannel | — | |
player.cycleRepeatMode | Player: Cycle Repeat Mode (Off → All → One) | Mixer | playerChannel | — | |
player.toggleShuffle | Player: Toggle Shuffle | Mixer | playerChannel | — | |
generator.cycleWaveform | Generator: Cycle Waveform (Sine → Pink → White → Click) | Mixer | generatorChannel | — | |
soundboard.stopChannel | Soundboard: Stop | Mixer | soundboardChannel | — | |
bus.startRecording | Bus: Start Recording | Recorder | recorderBus | — | |
bus.stopRecording | Bus: Stop Recording | Recorder | recorderBus | — | |
bus.toggleRecording | Bus: Start / Stop Recording | Recorder | recorderBus | — | |
bus.setRouteActive | Bus Route On/Off | Routing | bus + secondary bus | — | ✓ |
channel.setSendActive | Channel→Bus Send On/Off | Routing | channel + secondary bus | — | ✓ |
channel.setSendDb | Channel→Bus Send Level | Routing | channel + secondary bus | value (dB) | |
scene.recall | Recall Scene | Scenes | — | value (scene index) | |
engine.toggleRunning | Start / Stop Engine | Engine | — | — | ✓ |
mixer.adjustFaderDb's result is clamped to [-96, +12] dB server-side, so repeated deltas (e.g. from a held key) can't run a fader out of range.
soundboard.triggerPad (trigger a specific pad, requires_secondary_target: true — the pad's own id, supports_momentary: true for Hold-to-play pads) exists in the engine and ListActions does return it, but it's not practical to drive from an integration today: a pad's id only exists inside one specific Soundboard channel's own pad list, and neither StreamState nor the Mixer API currently exposes pad ids or names — there's no way to discover a valid secondary_target_id remotely. soundboard.stopChannel (no secondary target, listed above) is the one Soundboard action that's actually usable over the API right now.
Example call sequence
ListActionsonce, at startup — build your picker / cache the catalog.StreamState— keep it open for the life of your integration; use it to resolve names → IDs and to keep any live indicators (button icon state) current.InvokeActionon whatever triggers your integration (button press, etc.) — checkok.
See the worked example for this end-to-end in Node.js.