Summary

The Companion Satellite API is a TCP (and WebSocket) line-protocol that allows remote "surfaces" (e.g. Stream Deck devices) to register with a Bitfocus Companion instance, receive streamed button state (bitmaps, colors, text), and report user interactions (presses, encoder rotations, variable updates). The protocol also supports a button subscription mode for observing individual buttons without registering a full surface.

Transport

protocols:
  - tcp
addressing:
  port: 16622
auth:
  type: UNRESOLVED
framing:
  terminators:
    - LF
    - CRLF
  arguments: COMMAND-NAME NAME=value separated by spaces; double-quote values containing spaces
  booleans: Send true/false or0/1; receive0/1
notes: TCP default16622; alternate ports supported. WebSocket default16623 since Companion3.5; source does not specify URL path/TLS/auth. No authentication claim inferred.

Traits

[]

Actions

- id: ping
  label: Ping
  kind: action
  params:
    - name: payload
      type: string
      description: Arbitrary payload echoed back
      required: true
  command: PING {payload}
  terminator: LF or CRLF
  description: Send periodically; source recommends every two seconds to avoid an idle disconnect. Server responds PONG with the same arbitrary payload.
- id: quit
  label: Quit
  kind: action
  params: []
  command: QUIT
  terminator: LF or CRLF
  description: Close connection and remove all registered devices.
- id: add_device
  label: Add Device
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique identifier for the device within the session
      required: true
    - name: PRODUCT_NAME
      type: string
      description: Product name shown in Companion UI
      required: true
    - name: SERIAL
      type: string
      description: Stable hardware serial number (since v1.10.0)
      required: false
    - name: KEYS_TOTAL
      type: integer
      description: "Simple mode only: default32. Before1.5.1 range1..32; since1.5.1 any integer>=1."
      required: false
      min: 1
      default: 32
    - name: KEYS_PER_ROW
      type: integer
      description: "Simple mode only: default8. Before1.5.1 range1..8; since1.5.1 any integer>=1."
      required: false
      min: 1
      default: 8
    - name: BITMAPS
      type: string
      description: "Simple mode only: before1.5 boolean defaulttrue; since1.5 bitmap size,0/false disables,1/true means72px,default72. Preserve selected version-specific wire spelling."
      required: false
    - name: COLORS
      type: string
      description: "Simple mode: before1.6 true/false; since1.6 true/false/hex/rgb. true and hex select hexadecimal; rgb selects CSS rgb without spaces; defaultfalse."
      required: false
      enum:
        - "true"
        - "false"
        - hex
        - rgb
    - name: TEXT
      type: boolean
      description: Simple mode; stream button text,defaultfalse.
      required: false
      default: false
    - name: TEXT_STYLE
      type: boolean
      description: Since1.4; simple mode text style properties,defaultfalse.
      required: false
      default: false
    - name: LAYOUT_MANIFEST
      type: string
      description: "Since1.9 base64 JSON object with required stylePresets.default and controls. Controls map alphanumeric/-/slash IDs to required zero-based row,column and optional stylePreset(default default). Style presets: bitmap {w,h},colors hex/rgb,text,textStyle; since1.13 leds {segments>=1,mode full-ring/simple}. Ignores KEYS_TOTAL,KEYS_PER_ROW,BITMAPS,COLORS,TEXT,TEXT_STYLE. Full vendor schema URL is in Notes."
      required: false
    - name: BRIGHTNESS
      type: boolean
      description: Since1.7; device supports brightness changes; defaulttrue.
      required: false
      default: true
    - name: VARIABLES
      type: string
      description: "Since1.7 base64 JSON array: each item id,type(input/output),name,description. Input is satellite-produced; output streams to satellite."
      required: false
    - name: PINCODE_LOCK
      type: string
      description: Since1.8 FULL handles display and input; PARTIAL handles display only (currently same behavior, future distinction possible).
      required: false
      enum:
        - FULL
        - PARTIAL
    - name: CONFIG_FIELDS
      type: string
      description: Since1.10 base64 JSON array of config field definitions; vendor schema in Notes. Values arrive in DEVICE-CONFIG immediately after registration and on UI change.
      required: false
    - name: CAN_CHANGE_PAGE
      type: string
      description: Label string indicating device can initiate page changes (since v1.10.0)
      required: false
    - name: SERIAL_IS_UNIQUE
      type: boolean
      description: Since API1.10; false for shared/nonunique hardware serials, disabling persistent unit identification from that serial. Default true.
      required: false
      default: true
    - name: BITMAP_FORMAT
      type: string
      description: Since1.12; request only a format in CAPS BITMAP_FORMATS. Omitted or unadvertised format falls back to rgb; older servers ignore this parameter and send rgb.
      required: false
      enum:
        - rgb
        - png
        - webp
      default: rgb
  command: ADD-DEVICE DEVICEID={DEVICEID} PRODUCT_NAME="{PRODUCT_NAME}"
  terminator: LF or CRLF
  description: Register simple or advanced surface. Append only supplied optional NAME=value arguments; quote values with spaces. LAYOUT_MANIFEST selects advanced mode and ignores all simple rendering parameters. Stream KEY-STATE updates after registration. DEVICEID is the session routing key; SERIAL supplies persistent identity on API1.10+.
- id: remove_device
  label: Remove Device
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique identifier used to add the device
      required: true
  command: REMOVE-DEVICE DEVICEID={DEVICEID}
  terminator: LF or CRLF
- id: key_press
  label: Key Press
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique device identifier
      required: true
    - name: KEY
      type: string
      description: Simple mode key number; since1.6 may instead use local zero-based row/column such as0/0. Version-dependent key limits follow ADD-DEVICE.
      required: false
    - name: CONTROLID
      type: string
      description: Advanced mode only,API1.9+; exact alphanumeric/-/slash control ID from LAYOUT_MANIFEST.
      required: false
    - name: PRESSED
      type: boolean
      description: True for press, false for release
      required: true
  command: KEY-PRESS DEVICEID={DEVICEID} KEY={KEY} PRESSED={PRESSED}
  terminator: LF or CRLF
  command_advanced: KEY-PRESS DEVICEID={DEVICEID} CONTROLID="{CONTROLID}" PRESSED={PRESSED}
  description: Use KEY only in simple mode, CONTROLID only in advanced mode(API1.9+); never send both.
- id: key_rotate
  label: Key Rotate
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique device identifier
      required: true
    - name: KEY
      type: string
      description: Simple mode key number; since1.6 may instead use local zero-based row/column such as0/0. Version-dependent key limits follow ADD-DEVICE.
      required: false
    - name: CONTROLID
      type: string
      description: Advanced mode only,API1.9+; exact alphanumeric/-/slash control ID from LAYOUT_MANIFEST.
      required: false
    - name: DIRECTION
      type: integer
      description: "Signed direction and step count: positive right/clockwise,negative left;1/-1 one step;0 is legacy one-step-left. Magnitudes>1 require API1.14+ and CAPS ROTARY_AMOUNT=1. Source also says older servers treat any nonzero value as one step; its direction wording is ambiguous,so legacy negative-value direction remains unresolved; the unambiguous legacy directions are1 right and0 left."
      required: true
  command: KEY-ROTATE DEVICEID={DEVICEID} KEY={KEY} DIRECTION={DIRECTION}
  terminator: LF or CRLF
  command_advanced: KEY-ROTATE DEVICEID={DEVICEID} CONTROLID="{CONTROLID}" DIRECTION={DIRECTION}
  description: Use KEY only in simple mode, CONTROLID only in advanced mode(API1.9+); never send both. Rotation also requires the per-bank checkbox to be enabled in Companion.
  since: 1.3.0
- id: set_variable_value
  label: Set Variable Value
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique device identifier
      required: true
    - name: VARIABLE
      type: string
      description: Variable ID as defined in ADD-DEVICE
      required: true
    - name: VALUE
      type: string
      description: Base64-encoded variable value
      required: true
  command: SET-VARIABLE-VALUE DEVICEID={DEVICEID} VARIABLE="{VARIABLE}" VALUE="{VALUE}"
  terminator: LF or CRLF
  since: 1.7.0
  description: 'For declared input variables; VALUE is base64 of the variable value. Since1.7.1 success echoes variable name: SET-VARIABLE-VALUE OK VARIABLE="{VARIABLE}".'
- id: pincode_key
  label: Pincode Key Press
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique device identifier
      required: true
    - name: KEY
      type: integer
      description: Pincode digit0..9.
      required: true
      min: 0
      max: 9
  command: PINCODE-KEY DEVICEID={DEVICEID} KEY={KEY}
  terminator: LF or CRLF
  since: 1.8.0
  description: Report a pincode digit while handling pincode lock input; device KEY need not map directly to a surface button.
- id: change_page
  label: Change Page
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique device identifier
      required: true
    - name: DIRECTION
      type: integer
      description: 1 next page,0 previous page.
      required: true
      enum:
        - 0
        - 1
  command: CHANGE-PAGE DEVICEID={DEVICEID} DIRECTION={DIRECTION}
  terminator: LF or CRLF
  since: 1.10.0
  description: Valid only if CAN_CHANGE_PAGE declared at registration. If user disables checkbox, request is ignored but OK still returned. Obeys surface-group page order/restrictions.
- id: firmware_update_info
  label: Firmware Update Info
  kind: action
  params:
    - name: DEVICEID
      type: string
      description: Unique device identifier
      required: true
    - name: UPDATE_URL
      type: string
      description: URL to firmware update page; empty string clears notification
      required: true
  command: FIRMWARE-UPDATE-INFO DEVICEID={DEVICEID} UPDATE_URL="{UPDATE_URL}"
  terminator: LF or CRLF
  since: 1.10.0
  description: Nonempty URL shows firmware update indicator; empty quoted string clears it.
- id: add_sub
  label: Subscribe to Button
  kind: action
  params:
    - name: SUBID
      type: string
      description: Unique within connection; alphanumeric,-,/ characters. Reuse registered SUBID for subsequent messages.
      required: true
    - name: LOCATION
      type: string
      description: Button location in PAGE/ROW/COL format
      required: true
    - name: BITMAP
      type: string
      description: Simple style square size in pixels;0/false disables. Preserve chosen wire representation.
      required: false
    - name: COLORS
      type: string
      description: Simple style hex or CSS rgb.
      required: false
      enum:
        - hex
        - rgb
    - name: TEXT
      type: boolean
      description: Stream button text (default false)
      required: false
    - name: TEXT_STYLE
      type: boolean
      description: Stream text style (default false)
      required: false
    - name: STYLE
      type: string
      description: "Base64 JSON SatelliteControlStylePreset: bitmap {w,h} allows nonsquare;colors hex/rgb;text boolean;textStyle boolean;since1.13 leds {segments>=1,mode full-ring/simple}. Overrides simple options. Full vendor schema in Notes."
      required: false
    - name: BITMAP_FORMAT
      type: string
      description: Since1.12; request only a format in CAPS BITMAP_FORMATS. Omitted or unadvertised format falls back to rgb; older servers ignore this parameter and send rgb.
      required: false
      enum:
        - rgb
        - png
        - webp
      default: rgb
  command: ADD-SUB SUBID={SUBID} LOCATION={LOCATION}
  terminator: LF or CRLF
  since: 1.10.0
  capability: Require CAPS SUBSCRIPTIONS=1
  description: "Observe absolute PAGE/ROW/COL location. A valid PAGE/ROW/COL location containing no button is valid: OK then empty SUB-STATE. Set at least one style option for useful output. Append supplied optional NAME=value arguments. STYLE overrides BITMAP,COLORS,TEXT,TEXT_STYLE. SUB-STATE arrives immediately then when changed."
- id: remove_sub
  label: Unsubscribe from Button
  kind: action
  params:
    - name: SUBID
      type: string
      description: Unique within connection; alphanumeric,-,/ characters. Reuse registered SUBID for subsequent messages.
      required: true
  command: REMOVE-SUB SUBID={SUBID}
  terminator: LF or CRLF
  since: 1.10.0
  capability: Require CAPS SUBSCRIPTIONS=1
  description: Remove subscription; no further SUB-STATE for its SUBID.
- id: sub_press
  label: Subscription Button Press
  kind: action
  params:
    - name: SUBID
      type: string
      description: Unique within connection; alphanumeric,-,/ characters. Reuse registered SUBID for subsequent messages.
      required: true
    - name: PRESSED
      type: boolean
      description: True for press, false for release
      required: true
  command: SUB-PRESS SUBID={SUBID} PRESSED={PRESSED}
  terminator: LF or CRLF
  since: 1.10.0
  capability: Require CAPS SUBSCRIPTIONS=1
- id: sub_rotate
  label: Subscription Encoder Rotate
  kind: action
  params:
    - name: SUBID
      type: string
      description: Unique within connection; alphanumeric,-,/ characters. Reuse registered SUBID for subsequent messages.
      required: true
    - name: DIRECTION
      type: integer
      description: "Signed direction and step count: positive right/clockwise,negative left;1/-1 one step;0 is legacy one-step-left. Magnitudes>1 require API1.14+ and CAPS ROTARY_AMOUNT=1. Source also says older servers treat any nonzero value as one step; its direction wording is ambiguous,so legacy negative-value direction remains unresolved; the unambiguous legacy directions are1 right and0 left."
      required: true
  command: SUB-ROTATE SUBID={SUBID} DIRECTION={DIRECTION}
  terminator: LF or CRLF
  since: 1.10.0
  capability: Require CAPS SUBSCRIPTIONS=1
  description: Rotation actions must be enabled for the button in Companion.
- id: pong
  label: Answer server keepalive
  kind: action
  command: PONG {payload}
  terminator: LF or CRLF
  params:
    - name: payload
      type: string
      required: true
      description: Echo the exact arbitrary payload from the server PING.
  description: Required response to server PING. Other unsolicited messages do not expect responses.

Feedbacks

- id: begin
  type: event
  description: First connection message. Use ApiVersion semver for compatibility; CompanionVersion is informational only. API1.10+ immediately sends CAPS next.
  pattern: BEGIN CompanionVersion={CompanionVersion} ApiVersion={ApiVersion}
  direction: server_to_client
- id: caps
  type: event
  description: "API1.10+ capability flags: SUBSCRIPTIONS;1.11+NONSQUARE;1.12+BITMAP_FORMATS comma-separated rgb,png,webp with rgb always;1.14+ROTARY_AMOUNT. Missing flags disabled. Availability changes close connection; reconnect/re-read. Before1.10 no CAPS; use ApiVersion for feature existence."
  pattern: CAPS {capabilities}
  direction: server_to_client
- id: key_state
  type: event
  description: Use KEY in simple mode or CONTROLID in advanced1.9+; DEVICEID routes surface. Optional LOCATION absolute page/row/column since1.10,not always present. TYPE and PRESSED since1.1. TYPE enum BUTTON/PAGEUP/PAGEDOWN/PAGENUM. Style-dependent optional BITMAP,COLOR,TEXTCOLOR,TEXT,FONT_SIZE,LEDS. BITMAP bare base64 raw RGB by default,or since1.12 negotiated png/webp self-describing data URL. COLOR/TEXTCOLOR hex or CSS RGB;TEXT base64 text;FONT_SIZE numeric. LEDS since1.13 always base64 raw RGB3bytes/segment,absent meansoff,independent of bitmap encoding. No response expected.
  pattern: KEY-STATE DEVICEID={DEVICEID} {state_fields}
  direction: server_to_client
- id: keys_clear
  type: event
  description: Resets all keys to black for a device.
  pattern: KEYS-CLEAR DEVICEID={DEVICEID}
  direction: server_to_client
- id: brightness
  type: event
  description: Set device brightness VALUE integer0..100.
  pattern: BRIGHTNESS DEVICEID={DEVICEID} VALUE={VALUE}
  direction: server_to_client
- id: variable_value
  type: event
  description: Since1.7; only declared output variables. VARIABLE is ID and VALUE is base64 encoded value.
  pattern: VARIABLE-VALUE DEVICEID={DEVICEID} VARIABLE="{VARIABLE}" VALUE="{VALUE}"
  direction: server_to_client
- id: locked_state
  type: event
  description: "PINCODE_LOCK declared: LOCKED and CHARACTER_COUNT;optional ROTATION since1.10.1 enum0,90,-90,180. While locked, drawing messages stop and input messages are ignored."
  pattern: LOCKED-STATE DEVICEID={DEVICEID} LOCKED={LOCKED} CHARACTER_COUNT={CHARACTER_COUNT}
  direction: server_to_client
- id: device_config
  type: event
  description: "When CONFIG_FIELDS declared: CONFIG is base64 JSON object keyed by field id; sent after ADD-DEVICE OK and on config change."
  pattern: DEVICE-CONFIG DEVICEID={DEVICEID} CONFIG="{CONFIG}"
  direction: server_to_client
- id: sub_state
  type: event
  description: Routes SUBID;TYPE and PRESSED. TYPE enum BUTTON/PAGEUP/PAGEDOWN/PAGENUM. Style-dependent optional BITMAP,COLOR,TEXTCOLOR,TEXT,FONT_SIZE,LEDS. BITMAP bare base64 raw RGB by default,or since1.12 negotiated png/webp self-describing data URL. COLOR/TEXTCOLOR hex or CSS RGB;TEXT base64 text;FONT_SIZE numeric. LEDS since1.13 always base64 raw RGB3bytes/segment,absent meansoff,independent of bitmap encoding. No response expected.
  pattern: SUB-STATE SUBID={SUBID} TYPE={TYPE}
  direction: server_to_client
- id: pong
  type: event
  description: Response to PING. Echoes the payload.
  pattern: PONG {payload}
  direction: server_to_client
- id: error
  type: event
  description: 'Unknown command uses ERROR MESSAGE="Unknown command: ..."; known-command error uses command prefix; DEVICEID included since1.2 when known.'
  pattern: ERROR MESSAGE="{MESSAGE}"
  direction: server_to_client
  patterns:
    - ERROR MESSAGE="{MESSAGE}"
    - '{COMMAND_NAME} ERROR MESSAGE="{MESSAGE}"'
    - '{COMMAND_NAME} ERROR DEVICEID={DEVICEID} MESSAGE="{MESSAGE}"'
- id: ping
  type: event
  pattern: PING {payload}
  description: Server keepalive requires client PONG with exact payload.
- id: command_ok
  type: event
  patterns:
    - "{COMMAND_NAME} OK"
    - "{COMMAND_NAME} OK {arguments}"
  description: Known-command success. Additional fields depend on command,including variable echo since1.7.1.

Variables

[]

Events

[]

Macros

[]

Safety

confirmation_required_for: []
interlocks: []
# UNRESOLVED: populate if source contains safety warnings, interlock procedures,
# or power-on sequencing requirements. Never infer - only populate from explicit source text.

Notes

  • Source: https://companion.free/for-developers/Satellite-API/ ; exact publisher Markdown snapshot fetched 2026-09-26, pinned by the author manifest. Covers API through1.14. Per-command/version/capability prerequisites apply; this does not assert all releases support all features.
  • Client commands have LF or CRLF terminators. Templates show required fields; append optional parameters only when supplied,as space-separated NAME=value,quoting strings with spaces. KEY versus CONTROLID are mutually exclusive mode-specific variants. The document does not specify escaping embedded double quotes; that remains unresolved.
  • Known commands return COMMAND-NAME OK (optional fields) or COMMAND-NAME ERROR MESSAGE=... (DEVICEID since1.2 ifknown); unknowncommands ERROR MESSAGE=... . PING/PONG is the keepalive exception. Do not acknowledge unsolicited state events except PING.
  • Advanced surface schema: https://github.com/bitfocus/companion/blob/main/assets/satellite-surface.schema.json ; config fields schema: https://github.com/bitfocus/companion/blob/main/assets/satellite-config-fields.schema.json . Linked schemas are external and have not been independently expanded here; top-level shapes stated in the API document are preserved.
  • API→Companion introduction:1.4→3.0;1.5→3.2;1.7→3.4;1.8→4.0;1.9→4.2;1.10→4.3;1.11/1.12→5.0;1.13/1.14→5.1. Negotiate ApiVersion from BEGIN,not CompanionVersion.
  • Bitmap formats API1.12+:choose only CAPS BITMAP_FORMATS;rgb mandatoryfallback. rgb is bare base64 RGB;png/webp lossless data URLs. Check data: prefix on receipt. Older servers ignore BITMAP_FORMAT and returnrgb. Nonsquare capability is1.11; layouts may request nonsquare without it but receive black borders asneeded.
  • LEDs API1.13+:no separate CAPS flag; only advanced LAYOUT_MANIFEST or STYLE,not simple mode. segments>=1; mode full-ring or simple. full-ring segment0 at6o'clock,increasingclockwise,deadzoneblack;non-ring gauge fallsbacksimple. simple orders0% atsegment0 to100% atlast;ignoresgaugeangles. Remap forphysicalwiring. LEDS always rawRGB3bytes/segment,neverdataURL;absence meansoff.
  • API1.14 rotation magnitudes require CAPS ROTARY_AMOUNT=1. Preserve source's legacy wording explicitly; do not infer unsupported per-version direction behavior.
  • No fixed variable list: ADD-DEVICE declares input/output variables; state/config events are documented in Feedbacks. No query actions invented for unsolicited messages.
  • Source does not establish authentication,WebSocket path/TLS,message size limits,or maximum device/subscription counts. Hardware/application session not exercised.

Provenance

source_domains:
  - raw.githubusercontent.com
source_urls:
  - https://raw.githubusercontent.com/bitfocus/website/main/for-developers/Satellite-API.md
retrieved_at: 2026-09-26T14:23:19.600Z
last_checked_at: 2026-09-26T14:23:19.600Z

Verification Summary

verdict: verified
checked_at: 2026-09-26T14:23:19.600Z
matched_actions: 15
action_count: 15
confidence: medium
summary: "Complete exact-publisher API1.14 guide independently reviewed:15 client commands including required PONG,all14 prior IDs,optional/mode-specific parameters,version/capability gates and13 feedbacks match after3 wording corrections;unsolicited messages are not counted as client commands;auth,quote escaping and external nested-schema details remain explicitly unresolved/unexpanded. (2 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "no authentication mechanism described; source does not specify if auth can be configured"
- "populate if source contains safety warnings, interlock procedures,"

From the AI4AV catalog (https://ai4av.net) · ODbL-1.0