Satellite API
It is possible to remotely connect a 'Stream Deck' to companion so that it appears as its own device and follows the paging model. This is different from how the OSC/TCP/UDP servers operate.
This page documents the protocol. The intention is to only ever add non-breaking functionality to this API, and to keep this document updated with new functionality as it is added.
Companion version support
This lists what versions of Companion introduced support for each API version.
| API Version | Companion Versions |
|---|---|
| 1.4 | v3.0+ |
| 1.5 | v3.2+ |
| 1.7 | v3.4+ |
| 1.8 | v4.0+ |
| 1.9 | v4.2+ |
| 1.10 | v4.3+ |
Connection
The server by default runs on port TCP 16622, but this will become configurable in the future. You should make sure to support alternate ports to allow for future compatibility as well as firewalls or router port forwarding.
As of Companion 3.5, it is also possible to use this protocol over websockets, with a default port of 16623.
Each message is presented as a line, with a \n or \r\n terminator.
Messages follow the general format of COMMAND-NAME ARG1=VAL1 ARG2=true ARG3="VAL3 with spaces"\n.
Key numbers are in the range of 0-31.
Note: You can send boolean values can as both true/false and 0/1, you will always receive them as 0/1
Upon connection you will receive BEGIN CompanionVersion=2.2.0-d9008309-3449 ApiVersion=1.0.0 stating the build of companion you are connected to. The CompanionVersion field should not be relied on to be meaningful to your application, but can be presented as information to the user, or to aid debugging. You should use the ApiVersion field to check compatibility with companion. The number followers semver for versioning. We hope to keep breaking changes to a minimum, and will do so only when necessary.
On servers that support it (since v1.10.0), BEGIN is immediately followed by a CAPS message declaring which optional features are available. See Capabilities below.
Messages to send
Upon receiving an unknown command, the server will respond with the format ERROR MESSAGE="Unknown command: SOMETHING"
Known commands will get either a success or error response like the following:
COMMAND-NAME ERROR MESSAGE="Some text here"\nCOMMAND-NAME ERROR DEVICEID=00000 MESSAGE="Some text here"\n(since v1.2.0,DEVICEIDis included when it is known)COMMAND-NAME OK\nCOMMAND-NAME OK ARG1=arg1\n
Close connection
QUIT
Close the connection, removing all registered devices
Ping/pong
PING payload
Check the server is alive, with an arbitrary payload
Responds with PONG payload
You must call this at an interval, we recommend every 2 seconds, this is to ensure the connection doesn't get closed from being idle.
Messages to receive
No responses are expected to these unless stated below, and to do so will result in an error.
Ping/pong
PING payload
The server is checking you are still alive, with an arbitrary payload
You must respond with PONG payload
Capabilities (Since v1.10.0)
CAPS SUBSCRIPTIONS=1
Sent by the server immediately after BEGIN, before any other messages. Declares which optional features are available in this session. If a flag is absent, the client should treat it as disabled.
SUBSCRIPTIONStrue/false whether the Button Subscription API (ADD-SUB,REMOVE-SUB,SUB-PRESS,SUB-ROTATE,SUB-STATE) is available
If the server changes the availability of an optional feature at runtime, it will close the connection. The client should reconnect and re-read the new CAPS message.
Note: servers older than v1.10.0 do not send CAPS. Clients should rely solely on the ApiVersion from BEGIN to determine whether a feature exists at all; CAPS only needs to be checked for features that may be conditionally disabled within a version that otherwise supports them.
Surfaces
The surface API is the primary way to use the Satellite protocol. It lets your client register one or more virtual surfaces with Companion — each surface appears in the Surfaces table in the UI just like a physical device, follows Companion's page model, and receives streamed button state updates (bitmaps, colours, text) that your client is responsible for rendering.
Two modes are available when registering a surface:
- Simple mode — a flat uniform grid of buttons with shared rendering settings. Easiest to implement and sufficient for most use cases.
- Advanced mode (since v1.9.0) — individually configurable controls, each with its own rendering style. Suited for mixed surfaces such as a grid of buttons alongside encoders.
Once a surface is registered with ADD-DEVICE, Companion will begin streaming KEY-STATE updates for every button on the surface. Your client reports user interactions (button presses, encoder rotations) back to Companion using KEY-PRESS and KEY-ROTATE.
Messages to send
Adding a satellite device
When adding a device, you need to choose between a simple and advanced mode. The advanced mode allows finer grained control definitions, but requires a bit more work. The simple mode is more basic but is sufficient for many use cases and is easier to implement.
ADD-DEVICE DEVICEID=00000 PRODUCT_NAME="Satellite Streamdeck"
DEVICEIDa unique identifier for this device within the current session. This is the routing key used to address the device in all subsequent messages. IfSERIALis not set, or talking to Companion before API v1.10.0, then this is used as the stable hardware serial number (SeeSERIALbelow for more)PRODUCT_NAMEis the name of the product to show in the Surfaces table in the UI
Optional parameters (all modes):
SERIAL- (added in v1.10.0) the stable hardware serial number or other persistent identifier for this device. Companion uses this value to match the device to its stored configuration across sessions. If not provided, Companion falls back to usingDEVICEIDfor config matching (preserving backward compatibility with older satellites). Recommended format istype:identifier(e.g.streamdeck:AB12CD34) to avoid collisions between device types.SERIAL_IS_UNIQUE- (added in v1.10.0) true/false whether theSERIALvalue uniquely identifies a single physical device. Set tofalsewhen the hardware does not provide a unique serial number (e.g. some devices report a shared product ID instead of a per-unit serial). Whenfalse, Companion will not rely on the serial for persistent identification of this specific unit. (default true)BRIGHTNESS- (added in v1.7.0) true/false whether the device supporting changing brightness (default true)VARIABLES- (added in v1.7.0) a base64 encoded json array describing any input or output variables supported for this device
Each item in the array should be of the form:{"id": "some-id", // This is the identifier used when sending/receiving a value for the variable"type": "input", // or "output". When set to `input`, this is a value that the satellite device produces. When `output`, a value will be streamed to the satellite device"name": "My value", // A user facing name for this variable"description": "Something longer about it. eg Supports values in range 0-100", // A longer user facing description of this variable}PINCODE_LOCK- (added in v1.8.0) you can set to indicate that you will handle display of the pincode locked state. set toFULLto indicate that you will handle display and input or toPARTIALto indicate that you will handle display and the user will not be able to input a pincode. (Partial mode has no difference in behaviour currently, but we will utilise it in the future)CONFIG_FIELDS- (added in v1.10.0) a base64-encoded JSON array of custom config field definitions to expose in the Companion UI for this device. See schema inassets/satellite-config-fields.schema.json. When provided, Companion will render these fields in the surface settings panel and push the stored values back to the device viaDEVICE-CONFIGafter the device is registered and again whenever the user changes them.CAN_CHANGE_PAGE- (added in v1.10.0) a label string indicating that the device is capable of initiating page changes (e.g. via a swipe gesture or dedicated page-up/down button). When provided, Companion adds a checkbox with this label to the surface settings panel, letting the user control whether the device is allowed to change pages. The device can then sendCHANGE-PAGEmessages to navigate between pages.
Simple mode
Describe the surface as a flat grid of uniform buttons. All buttons share the same rendering settings.
KEYS_TOTAL- number of keys the device has. (default 32) Valid values varies depending on API Version:- Since 1.5.1, this can be any integer value >= 1
- Before 1.5.1, must be in the range 1-32
KEYS_PER_ROW- number of keys per row. (default 8) Valid values varies depending on API Version:- Since 1.5.1, this can be any integer value >= 1
- Before 1.5.1, must be in the range 1-8
BITMAPS- This varies depending on API Version:- Since 1.5.0, this is a number specifying the desired size of the bitmaps. If 0 or false, then bitmaps will not be streamed. If 1 or true, they will be 72px (default 72)
- Before 1.5.0, this is true/false whether you want to be streamed bitmaps for display on the buttons (default true)
COLORS- This varies depending on API Version:- Since 1.6.0 true/false/'hex'/'rgb'
- Before 1.6 true/false whether you want to be streamed colors for display on the buttons and in which format (default false).
If you specify true or 'hex', you'll get color readouts in hexadecimal notation, if you specify 'rgb', you'll get color readouts in css rgb notation without spaces.
TEXT- true/false whether you want to be streamed button text for display on the buttons (default false)TEXT_STYLE- (added in v1.4.0) true/false whether you want to be streamed text style information for display on the buttons (default false)
In simple mode, KEY-PRESS, KEY-ROTATE and KEY-STATE use KEY to identify controls.
Advanced mode (since v1.9.0)
Describe a surface with individually configurable controls, where each control can have its own rendering settings. When LAYOUT_MANIFEST is provided, the simple mode parameters (KEYS_TOTAL, KEYS_PER_ROW, BITMAPS, COLORS, TEXT, TEXT_STYLE) are ignored. KEY-PRESS, KEY-ROTATE and KEY-STATE use CONTROLID to identify controls by the ID defined in the manifest.
LAYOUT_MANIFEST- a base64-encoded JSON object describing the surface layout. The full schema is defined inassets/satellite-surface.schema.json.
The manifest has two top-level properties:
stylePresets— a named map of rendering style presets. Thedefaultpreset is required and is used as the fallback for any control that does not specify its own. Each preset can define:bitmap— if set, bitmaps of the given pixel dimensions will be streamed, e.g.{ "w": 72, "h": 72 }colors— stream colour data;"hex"for hexadecimal notation or"rgb"for CSS rgb notationtext—trueto stream button texttextStyle—trueto stream text style properties (e.g. font size)
controls— a map of control IDs to their definitions. The ID (alphanumeric,-,/) is what gets used asCONTROLIDin subsequent messages. Each entry defines:row— zero-based row index (required)column— zero-based column index (required)stylePreset— name of a style preset to use for this control (optional, defaults todefault)
Example manifest (before base64 encoding):
{
"stylePresets": {
"default": { "bitmap": { "w": 72, "h": 72 }, "colors": "hex" },
"encoder": { "colors": "hex" }
},
"controls": {
"0/0": { "row": 0, "column": 0 },
"0/1": { "row": 0, "column": 1 },
"enc/0": { "row": 0, "column": 2, "stylePreset": "encoder" }
}
}
Removing a satellite device
REMOVE-DEVICE DEVICEID=00000
DEVICEIDthe unique identifier used to add the device
Pressing a key
Simple mode: KEY-PRESS DEVICEID=00000 KEY=0 PRESSED=true
Advanced mode (since v1.9.0): KEY-PRESS DEVICEID=00000 CONTROLID="0/0" PRESSED=true
DEVICEIDthe unique identifier used to add the deviceKEY(simple mode) number of the key which is pressed/released. Since v1.6 this can be either a legacy key number or the local row/column starting at top left with0/0and counting up towards bottom/rightCONTROLID(advanced mode, since v1.9.0) the ID of the control as defined in theLAYOUT_MANIFESTPRESSEDtrue/false whether the key is pressed
Rotating an encoder (Since v1.3.0)
Note: there is a checkbox to enable this per bank inside Companion, allowing users to define the actions to execute
Simple mode: KEY-ROTATE DEVICEID=00000 KEY=0 DIRECTION=1
Advanced mode (since v1.9.0): KEY-ROTATE DEVICEID=00000 CONTROLID="enc/0" DIRECTION=1
DEVICEIDthe unique identifier used to add the deviceKEY(simple mode) number of the key/encoder which is rotated. Since v1.6 this can be either a legacy key number or the local row/column starting at top left with0/0and counting up towards bottom/rightCONTROLID(advanced mode, since v1.9.0) the ID of the control as defined in theLAYOUT_MANIFESTDIRECTIONdirection of the rotation. 1 for right, -1 for left
Updating a variable (Since v1.7.0)
This can be used when input variables are defined as part of ADD-DEVICE.
SET-VARIABLE-VALUE DEVICEID=00000 VARIABLE="some-id" VALUE="abc="
DEVICEIDthe unique identifier used to add the deviceVARIABLEthe id of the variable being updatedVALUEthe value of the variable, base64 encoded. The encoding is so that special characters and newlines don't have to be escaped, avoiding a wide range of easy to trigger bugs.
The success response echoes the variable name: SET-VARIABLE-VALUE OK VARIABLE="some-id" (since v1.7.1)
Pincode key press (Since v1.8.0)
When handling the pincode locked state yourself, report a pincode key was pressed
PINCODE-KEY DEVICEID=00000 KEY=1
DEVICEIDthe unique identifier used to add the deviceKEYthe value of the pressed key (0-9)
Note: depending on your surface, this may not translate directly to a button press.
Changing page (Since v1.10.0)
Request that Companion navigate the surface to the next or previous page. This message is only valid if CAN_CHANGE_PAGE was set when adding the device.
The request is silently ignored if the user has disabled the page-change checkbox for this surface in the settings UI. Companion will always respond with OK.
CHANGE-PAGE DEVICEID=00000 DIRECTION=1
DEVICEIDthe unique identifier used to add the deviceDIRECTIONdirection to navigate.1for next page,0for previous page. Next/previous respects Companion's page order and any page restrictions configured for the surface group.
Firmware update available (Since v1.10.0)
Notify Companion that a firmware update is available (or no longer available) for this device. When UPDATE_URL is set to a non-empty value, Companion will show a firmware update indicator in the UI with a link to that URL. Set UPDATE_URL to an empty string to clear the update notification.
FIRMWARE-UPDATE-INFO DEVICEID=00000 UPDATE_URL="https://example.com/firmware"
FIRMWARE-UPDATE-INFO DEVICEID=00000 UPDATE_URL=""
DEVICEIDthe unique identifier used to add the deviceUPDATE_URLURL to the firmware update page or download; set to empty string to clear the update notification
Messages to receive
No responses are expected to these unless stated below, and to do so will result in an error.
State change for key
Simple mode: KEY-STATE DEVICEID=00000 KEY=0 BITMAP=abcabcabc COLOR=#00ff00
Advanced mode (since v1.9.0): KEY-STATE DEVICEID=00000 CONTROLID="0/0" BITMAP=abcabcabc COLOR=#00ff00
DEVICEIDthe unique identifier of the deviceKEY(simple mode) number of the key which the pixel buffer is forCONTROLID(advanced mode, since v1.9.0) the ID of the control as defined in theLAYOUT_MANIFESTTYPEtype of the key. (added in v1.1.0) EitherBUTTON,PAGEUP,PAGEDOWNorPAGENUMPRESSEDtrue/false whether the key is currently held down. (added in v1.1.0)LOCATION(since v1.10.0) the absolute location of the button in the formatpage/row/column(e.g.3/1/0). This is sent for all button types, but is not always set.
Optional parameters (sent based on the control's resolved style preset):
BITMAPbase64 encoded pixel data. Sent when the control's style preset hasbitmapset (simple mode: whenBITMAPSwas enabled). Resolution follows the size defined in the style preset. Currently encoded as 8-bit RGB (this may be configurable in the future).COLORhex or css encoded 8-bit RGB color for the key background. Sent when the control's style preset hascolorsset (simple mode: whenCOLORSwas set)TEXTCOLORhex or css encoded 8-bit RGB color for the key text. Sent when the control's style preset hascolorsset (simple mode: whenCOLORSwas set) (added in v1.6)TEXTbase64 encoded text as should be displayed on the key. Sent when the control's style preset hastextset (simple mode: whenTEXTwas true)FONT_SIZEnumeric size that should be used when displaying the text on the key. Sent when the control's style preset hastextStyleset (simple mode: whenTEXT_STYLEwas true) (added in v1.4.0)
Note: expect more parameters to be added to this message over time. Some could increase the frequency of the message being received.
Reset all keys to black
KEYS-CLEAR DEVICEID=00000
DEVICEIDthe unique identifier of the device
Change brightness
BRIGHTNESS DEVICEID=00000 VALUE=100
DEVICEIDthe unique identifier of the deviceVALUEbrightness number in range 0-100
Update of a variable (Since v1.7.0)
This can be received when output variables are defined as part of ADD-DEVICE.
VARIABLE-VALUE DEVICEID=00000 VARIABLE="some-id" VALUE="abc="
DEVICEIDthe unique identifier used to add the deviceVARIABLEthe id of the variable being updatedVALUEthe value of the variable, base64 encoded. The encoding is so that special characters and newlines don't have to be escaped, avoiding a wide range of easy to trigger bugs.
Locked state update (Since v1.8.0)
This can be received when PINCODE_LOCK was specified when adding the device
LOCKED-STATE DEVICEID=00000 LOCKED=true CHARACTER_COUNT=0
DEVICEIDthe unique identifier used to add the deviceLOCKEDwhether the surface is lockedCHARACTER_COUNThow many characters have been entered for the pincodeROTATION(optional) the current rotation of the surface in degrees (0, 90, -90, 180) (added in v1.10.1)
Between this reporting LOCKED=true and LOCKED=false, you will not receive any other drawing messages, and any input messages you send will be ignored.
Device config update (Since v1.10.0)
Sent when CONFIG_FIELDS was declared in ADD-DEVICE. If your surface defines any config fields, Companion will send this message once immediately after the device is registered (ADD-DEVICE OK) and again whenever the user changes a config value in the UI.
DEVICE-CONFIG DEVICEID=00000 CONFIG="eyJteS1maWVsZCI6InNvbWUtdmFsdWUifQ=="
DEVICEIDthe unique identifier used to add the deviceCONFIGbase64-encoded JSON object where each key is a fieldidfromCONFIG_FIELDSand the value is the current stored value for that field
Button Subscriptions (Since v1.10.0)
The subscription API lets a client observe any individual button at an absolute location in Companion — without registering a surface. This is useful for custom UIs, secondary displays, or any scenario where you want to monitor or interact with a specific button rather than presenting a full surface to Companion.
Each subscription is identified by a client-chosen SUBID. The SUBID may contain alphanumeric characters, -, and / (the same rules as CONTROLID). It must be unique within the connection.
A location is expressed as PAGE/ROW/COL using Companion's native location syntax, e.g. 1/2/3 for page 1, row 2, column 3.
Subscribing to a location that does not contain a button is valid — Companion will respond with OK and immediately stream an empty button.
Messages to send
Subscribe to a button
ADD-SUB SUBID=myid LOCATION=1/2/3
SUBIDunique identifier for this subscription, chosen by the clientLOCATIONthe button location inPAGE/ROW/COLformat
Two modes are available for specifying what should be streamed. At least one style option should be set for useful output.
Simple style
Flat parameters, mirrors the simple surface mode:
BITMAPa number specifying the desired square bitmap size in pixels. If 0 or false, bitmaps will not be streamed.COLORSstream colour data;hexfor hexadecimal notation orrgbfor CSS rgb notationTEXTtrue/false whether you want button text streamed (default false)TEXT_STYLEtrue/false whether you want text style properties streamed (default false)
Advanced style
STYLEa base64-encoded JSON object following theSatelliteControlStylePresetschema defined inassets/satellite-surface.schema.json. WhenSTYLEis provided, the simple style parameters (BITMAP,COLORS,TEXT,TEXT_STYLE) are ignored.
The object can define:
bitmap— if set, bitmaps of the given pixel dimensions will be streamed, e.g.{ "w": 72, "h": 72 }. Unlike the simple modeBITMAP, this allows non-square dimensions.colors— stream colour data;"hex"for hexadecimal notation or"rgb"for CSS rgb notationtext—trueto stream button texttextStyle—trueto stream text style properties (e.g. font size)
Example STYLE value (before base64 encoding):
{ "bitmap": { "w": 72, "h": 72 }, "colors": "hex", "text": true }
This matches the json format used for the surface advanced mode.
Upon success, Companion immediately sends a SUB-STATE message with the current state of the button.
Unsubscribe from a button
REMOVE-SUB SUBID=myid
SUBIDthe identifier of the subscription to remove
No further SUB-STATE messages will be sent for this SUBID.
Reporting a button press
SUB-PRESS SUBID=myid PRESSED=true
SUBIDthe subscription identifierPRESSEDtrue/false whether the button is pressed
Reporting an encoder rotation
SUB-ROTATE SUBID=myid DIRECTION=1
SUBIDthe subscription identifierDIRECTIONdirection of the rotation. 1 for right, -1 for left
Note: there is a checkbox to enable rotation actions per button inside Companion, allowing users to define the actions to execute.
Messages to receive
No response is expected to these messages.
Button state update
SUB-STATE SUBID=myid TYPE=BUTTON
Sent immediately after a successful ADD-SUB and again whenever the button's state changes.
SUBIDthe subscription identifierTYPEtype of the location. EitherBUTTON,PAGEUP,PAGEDOWNorPAGENUMPRESSEDtrue/false whether the button is currently held down.
Optional parameters (sent based on the style options specified in ADD-SUB):
BITMAPbase64 encoded pixel data. Sent whenBITMAPwas set inADD-SUB. Resolution matches the size requested. Currently encoded as 8-bit RGB (this may be configurable in the future).COLORhex or css encoded 8-bit RGB color for the button background. Sent whenCOLORSwas set inADD-SUB.TEXTCOLORhex or css encoded 8-bit RGB color for the button text. Sent whenCOLORSwas set inADD-SUB.TEXTbase64 encoded text as should be displayed on the button. Sent whenTEXT=truewas set inADD-SUB.FONT_SIZEnumeric size that should be used when displaying the text on the button. Sent whenTEXT_STYLE=truewas set inADD-SUB.
Note: expect more parameters to be added to this message over time. Some could increase the frequency of the message being received.