Summary

SiriusXM does not expose a vendor-specific IP control protocol. On Bluesound and NAD hardware, SiriusXM is delivered as a streaming source inside the BluOS ecosystem and is driven through the standard BluOS Custom Integration HTTP API. This spec documents that API as it applies to any BluOS player on which SiriusXM is available as a source — transport is HTTP GET over TCP, port 11000, returning UTF-8 XML.

Transport

protocols:
  - http
addressing:
  port: 11000
  base_url: "/"
auth:
  type: none  # inferred: no auth procedure in source

The source also documents a UDP broadcast discovery protocol called LSDP on UDP port 11430 (registered with IANA for Lenbrook). It is not a control transport and is not enumerated as a protocol here; see the Notes section.

Traits

- powerable       # inferred from /reboot endpoint (soft reboot)
- routable        # inferred from /Play?inputTypeIndex=, /Play?inputIndex=, /Play?url= active-input endpoints
- queryable       # inferred from /Status, /SyncStatus, /Playlist, /Presets, /Settings endpoints
- levelable       # inferred from /Volume endpoints (level / dB / mute)

Actions

# Status queries
- id: status_query
  label: Playback Status Query
  kind: query
  command: "GET /Status[?timeout={seconds}&etag={etag}]"
  params: []
  notes: "Returns playback state, track, volume, mute, service, etc. Supports long-polling."

- id: sync_status_query
  label: Player and Group Sync Status Query
  kind: query
  command: "GET /SyncStatus[?timeout={seconds}&etag={etag}]"
  params: []
  notes: "Returns player info (brand, model, name, mac, ip:port) and grouping (master, slaves, volume). Supports long-polling."

# Volume
- id: set_volume_level
  label: Set Volume (Level 0-100)
  kind: action
  command: "GET /Volume?level={level}&tell_slaves={0|1}"
  params:
    - name: level
      type: integer
      description: Absolute volume 0-100
    - name: tell_slaves
      type: integer
      description: 0 = this player only; 1 = apply to all grouped players

- id: set_volume_abs_db
  label: Set Volume (Absolute dB)
  kind: action
  command: "GET /Volume?abs_db={db}&tell_slaves={0|1}"
  params:
    - name: abs_db
      type: number
      description: Absolute volume in dB (constrained to configured available range, typically -80..0)

- id: set_volume_relative_db
  label: Set Volume (Relative dB)
  kind: action
  command: "GET /Volume?db={delta_db}&tell_slaves={0|1}"
  params:
    - name: db
      type: number
      description: Positive or negative dB delta

- id: volume_up
  label: Volume Up (relative dB)
  kind: action
  command: "GET /Volume?db={db_value}"
  params:
    - name: db_value
      type: number
      description: dB step (typical value 2)

- id: volume_down
  label: Volume Down (relative dB)
  kind: action
  command: "GET /Volume?db=-{db_value}"
  params:
    - name: db_value
      type: number
      description: dB step magnitude (typical value 2)

- id: mute_on
  label: Mute On
  kind: action
  command: "GET /Volume?mute=1"
  params: []

- id: mute_off
  label: Mute Off
  kind: action
  command: "GET /Volume?mute=0"
  params: []

# Playback control
- id: play
  label: Play (resume current track)
  kind: action
  command: "GET /Play"
  params: []

- id: play_seek
  label: Play with seek
  kind: action
  command: "GET /Play?seek={seconds}[&id={trackid}]"
  params:
    - name: seconds
      type: integer
      description: Position in current track
    - name: trackid
      type: integer
      description: Optional track id within the queue

- id: play_url
  label: Play stream URL
  kind: action
  command: "GET /Play?url={encodedStreamURL}"
  params:
    - name: encodedStreamURL
      type: string
      description: URL of streamed custom audio, URL-encoded

- id: pause
  label: Pause
  kind: action
  command: "GET /Pause"
  params: []

- id: pause_toggle
  label: Pause Toggle
  kind: action
  command: "GET /Pause?toggle=1"
  params: []

- id: stop
  label: Stop
  kind: action
  command: "GET /Stop"
  params: []

- id: skip
  label: Skip (next track)
  kind: action
  command: "GET /Skip"
  params: []
  notes: "Only valid when no <streamUrl> is present in /Status (i.e. using play queue)."

- id: back
  label: Back (previous track)
  kind: action
  command: "GET /Back"
  params: []
  notes: "Returns to start of current track if past 4 seconds, otherwise goes to previous track in queue."

- id: shuffle_set
  label: Shuffle On/Off
  kind: action
  command: "GET /Shuffle?state={0|1}"
  params:
    - name: state
      type: integer
      description: 0 = off, 1 = on

- id: repeat_set
  label: Repeat State
  kind: action
  command: "GET /Repeat?state={0|1|2}"
  params:
    - name: state
      type: integer
      description: "0 = repeat queue, 1 = repeat track, 2 = repeat off"

# Streaming radio station actions
- id: radio_skip
  label: Radio Station Skip
  kind: action
  command: "GET /Action?service={service_name}&skip={id}"
  params:
    - name: service_name
      type: string
      description: e.g. Slacker
    - name: id
      type: string
      description: Track id from <action url=...> in /Status

- id: radio_back
  label: Radio Station Back
  kind: action
  command: "GET /Action?service={service_name}&back={id}"
  params:
    - name: service_name
      type: string
    - name: id
      type: string

- id: radio_love
  label: Radio Station Love
  kind: action
  command: "GET /Action?service={service_name}&love={id}"
  params:
    - name: service_name
      type: string
    - name: id
      type: string

- id: radio_ban
  label: Radio Station Ban
  kind: action
  command: "GET /Action?service={service_name}&ban={id}"
  params:
    - name: service_name
      type: string
    - name: id
      type: string

# Play queue management
- id: playlist_list
  label: List Play Queue
  kind: query
  command: "GET /Playlist[?length=1][?start={first}&end={last}]"
  params:
    - name: length
      type: integer
      description: "If 1, return only top-level attributes (queue status)."
    - name: start
      type: integer
      description: First queue index (0-based) for pagination
    - name: end
      type: integer
      description: Last queue index for pagination

- id: playlist_delete
  label: Delete Track from Queue
  kind: action
  command: "GET /Delete?id={position}"
  params:
    - name: position
      type: integer
      description: Position in queue to delete

- id: playlist_move
  label: Move Track in Queue
  kind: action
  command: "GET /Move?new={destination}&old={origin}"
  params:
    - name: destination
      type: integer
      description: New track position
    - name: origin
      type: integer
      description: Old track position

- id: playlist_clear
  label: Clear Play Queue
  kind: action
  command: "GET /Clear"
  params: []

- id: playlist_save
  label: Save Play Queue as BluOS Playlist
  kind: action
  command: "GET /Save?name={playlist_name}"
  params:
    - name: playlist_name
      type: string
      description: Name for the saved playlist (URL-encoded)

# Presets
- id: presets_list
  label: List Presets
  kind: query
  command: "GET /Presets"
  params: []
  notes: "Presets are added/deleted only via the BluOS Controller app."

- id: preset_load
  label: Load Preset by Id
  kind: action
  command: "GET /Preset?id={presetId}"
  params:
    - name: presetId
      type: integer
      description: Numeric preset id from /Presets

- id: preset_next
  label: Load Next Preset
  kind: action
  command: "GET /Preset?id=+1"
  params: []

- id: preset_previous
  label: Load Previous Preset
  kind: action
  command: "GET /Preset?id=-1"
  params: []

# Browsing and searching
- id: browse
  label: Top-Level Browse
  kind: query
  command: "GET /Browse"
  params: []
  notes: "Returns a <browse> root with top-level sources, inputs and playlists."

- id: browse_descend
  label: Browse by Key
  kind: query
  command: "GET /Browse?key={key-value}[&withContextMenuItems=1]"
  params:
    - name: key_value
      type: string
      description: "browseKey / nextKey / parentKey / contextMenuKey / searchKey value (URL-encoded)"
    - name: withContextMenuItems
      type: integer
      description: Set to 1 to inline context menus

- id: browse_search
  label: Search within a Service
  kind: query
  command: "GET /Browse?key={key-value}&q={searchText}"
  params:
    - name: key_value
      type: string
      description: "searchKey value from a prior /Browse response (URL-encoded)"
    - name: searchText
      type: string
      description: "Search term (URL-encoded)"

# Player grouping
- id: add_slave_single
  label: Add One Secondary Player
  kind: action
  command: "GET /AddSlave?slave={secondaryPlayerIP}&port={secondaryPlayerPort}[&group={GroupName}]"
  params:
    - name: secondaryPlayerIP
      type: string
    - name: secondaryPlayerPort
      type: integer
      description: "Default 11000; CI580 uses 11000/11010/11020/11030"
    - name: group
      type: string
      description: Optional group name; BluOS picks a default if omitted

- id: add_slave_multiple
  label: Add Multiple Secondary Players
  kind: action
  command: "GET /AddSlave?slaves={secondaryPlayerIPs}&ports={secondaryPlayerPorts}"
  params:
    - name: secondaryPlayerIPs
      type: string
      description: Comma-separated IP list
    - name: secondaryPlayerPorts
      type: string
      description: Comma-separated port list

- id: remove_slave_single
  label: Remove One Secondary Player
  kind: action
  command: "GET /RemoveSlave?slave={secondaryPlayerIP}&port={secondaryPlayerPort}"
  params:
    - name: secondaryPlayerIP
      type: string
    - name: secondaryPlayerPort
      type: integer

- id: remove_slave_multiple
  label: Remove Multiple Secondary Players
  kind: action
  command: "GET /RemoveSlave?slaves={secondaryPlayerIPs}&ports={secondaryPlayerPorts}"
  params:
    - name: secondaryPlayerIPs
      type: string
      description: Comma-separated IP list
    - name: secondaryPlayerPorts
      type: string
      description: Comma-separated port list

# Reboot
- id: reboot
  label: Soft Reboot Player
  kind: action
  command: "POST /reboot (body: yes=1)"
  params: []
  notes: "POST with form data. Response is a human-readable 'Rebooting. Please close this window.' HTML page; not a structured XML."

# Doorbell chime
- id: doorbell_play
  label: Play Doorbell Chime
  kind: action
  command: "GET /Doorbell?play=1"
  params: []

# Bluetooth mode
- id: bluetooth_mode_set
  label: Set Bluetooth Mode
  kind: action
  command: "GET /audiomodes?bluetoothAutoplay={value}"
  params:
    - name: value
      type: integer
      description: "0 = Manual, 1 = Automatic, 2 = Guest, 3 = Disabled"

# Direct input selection
- id: input_active
  label: Active Input Selection (URL)
  kind: action
  command: "GET /Play?url={URL_value}"
  params:
    - name: URL_value
      type: string
      description: "URL attribute from /RadioBrowse?service=Capture response; only works for inputs appearing in that response"
  notes: "Use for active inputs and BluOS HUB inputs."

- id: input_external_legacy
  label: External Input by Index (FW 3.8.0 - 4.2.0)
  kind: action
  command: "GET /Play?inputIndex={IndexId}"
  params:
    - name: IndexId
      type: integer
      description: "1-based input index from /Settings?id=capture&shcemaVersion=32 in numerical order (Bluetooth excluded)"
  notes: "Documented for BluOS firmware newer than v3.8.0 and older than v4.2.0."

- id: input_external_typed
  label: External Input by Type-Index (FW 4.2.0+)
  kind: action
  command: "GET /Play?inputTypeIndex={type-index}"
  params:
    - name: type_index
      type: string
      description: "Format {input_type}-{index}; types include spdif, analog, coax, bluetooth, arc, earc, phono, computer, aesebu, balanced, microphone; index starts at 1"
  notes: "Documented for BluOS firmware v4.2.0 or newer."

# Capture / radio browse
- id: capture_list
  label: List Capture Inputs
  kind: query
  command: "GET /RadioBrowse?service=Capture"
  params: []
  notes: "Returns active inputs (Bluetooth, Analog, Optical, etc.) used as URL sources for /Play?url=."

- id: capture_settings
  label: Capture Settings (input list with indices)
  kind: query
  command: "GET /Settings?id=capture&schemaVersion=32"
  params: []
  notes: "Used to map inputIndex values for /Play?inputIndex=. Source notes 'shcemaVersion' typo in original (sic)."

# Context menu / add to queue
- id: add_to_queue
  label: Add Item to Play Queue (from context menu)
  kind: action
  command: "GET /Add?service={service}&albumid={albumid}[&playnow={-1|0|1}][&shuffle={0|1}][&where={nextAlbum|last|next}][&clear={0|1}]"
  params:
    - name: service
      type: string
      description: Music service id
    - name: albumid
      type: string
      description: Album or item id
    - name: playnow
      type: integer
      description: "-1 = don't start now; 0/1 = start now"
    - name: shuffle
      type: integer
      description: 0 or 1
    - name: where
      type: string
      description: nextAlbum | last | next - queue insertion position
    - name: clear
      type: integer
      description: 0 or 1 - clear existing queue first
  notes: "Specific parameter combinations are provided by the <actionURL> or <contextMenu> actionURL attributes in /Browse responses. Treat parameter shape as opaque and replay the URL verbatim."

- id: add_favourite
  label: Add Favourite
  kind: action
  command: "GET /AddFavourite?service={service}&albumid={albumid}"
  params:
    - name: service
      type: string
    - name: albumid
      type: string
  notes: "Specific parameter shape is given by the actionURL in context-menu <item> entries."

Feedbacks

- id: playback_state
  type: enum
  values: [play, pause, stop, stream, connecting]
  source: "/Status <state> element"

- id: volume_level
  type: integer
  range: "0-100 (or -1 for fixed volume)"
  source: "/Status and /Volume <volume> element"

- id: volume_db
  type: number
  source: "/Status and /Volume <db> attribute"

- id: mute_state
  type: integer
  range: "0 = unmuted, 1 = muted"
  source: "/Status and /Volume <mute> attribute"

- id: repeat_state
  type: integer
  range: "0 = repeat queue, 1 = repeat track, 2 = repeat off"
  source: "/Status <repeat> element"

- id: shuffle_state
  type: integer
  range: "0 = off, 1 = on"
  source: "/Status <shuffle> element"

- id: service
  type: string
  source: "/Status <service> element (e.g. Deezer, Tidal, Slacker, TuneIn, Spotify, etc.)"

- id: track_title
  type: string
  source: "/Status <title1>, <title2>, <title3> (preferred) or <album>, <artist>, <name>"

- id: position_secs
  type: integer
  source: "/Status <secs> element"

- id: total_length_secs
  type: integer
  source: "/Status <totlen> element"

- id: group_name
  type: string
  source: "/SyncStatus <SyncStatus group=...> attribute"

- id: bluetooth_battery_level
  type: integer
  range: "percent"
  source: "/Status <battery level=...> (only on players with battery)"

- id: etag
  type: string
  source: "Opaque value from /Status or /SyncStatus root attribute; used as long-polling cursor"

Variables

# UNRESOLVED: no continuous settable parameters beyond the discrete actions above.
# The /Volume endpoints already expose level, abs_db, db, mute as parameterized actions.
# The Bluetooth-mode endpoint /audiomodes?bluetoothAutoplay= is a discrete enum (see action bluetooth_mode_set).

Events

# The source does not document unsolicited event notifications.
# All state changes are surfaced through /Status and /SyncStatus long-polling.
#
# UNRESOLVED: whether the device pushes any unsolicited HTTP/SSE/UDP events
# (not described in the source).

Macros

# UNRESOLVED: the source does not describe device-side multi-step macros.
# The /Preset load action is a single-step convenience over the equivalent
# /Play?url= and /Add actions; it is not a multi-step macro.

Safety

confirmation_required_for: []
interlocks: []
# UNRESOLVED: source contains no safety warnings, interlocks, or power-on sequencing
# requirements. The /reboot endpoint is a soft reboot (no explicit hazard noted in source).

Notes

About SiriusXM specifically. SiriusXM is not exposed as a separate control API on Bluesound or NAD hardware. It is one of the streaming services available inside the BluOS ecosystem; selecting and playing SiriusXM stations uses the generic BluOS HTTP endpoints documented above (/Preset, /Browse, /Action, /Play). The source does not list a SiriusXM-specific endpoint, opcode, or service id string — discovery of SiriusXM is left to the /Browse and /Presets queries at runtime.

Polling etiquette. The source is explicit: when not using long-polling, limit regular polling to one request every 30 seconds. With long-polling, never make two consecutive identical-resource requests less than one second apart, even if the first returns fast. Recommended /Status long-poll timeout is 100 s (never faster than 10 s); recommended /SyncStatus long-poll timeout is 180 s.

Port and multi-node players. Port 11000 is the standard BluOS port. The NAD CI580 has four streamer nodes in one chassis: node 1 = 11000, node 2 = 11010, node 3 = 11020, node 4 = 11030. The actual port for a given node should be discovered via mDNS (musc.tcp, musp.tcp) or via LSDP (see below).

Reboot is a POST. /reboot is documented in the source as POST /reboot with form data (curl -d yes=1 192.168.1.100/reboot). Every other endpoint is a GET. The response to /reboot is plain HTML ("Rebooting. Please close this window. Please wait...") rather than the UTF-8 XML used by all other endpoints.

LSDP discovery (out of band). The source documents a separate UDP broadcast discovery protocol called LSDP on UDP port 11430 (registered with IANA for Lenbrook as of 27 March 2014). It is not a control protocol — it advertises BluOS players, servers, hubs, and pair-slaves via class IDs 0x0001–0x0008. Startup burst is 7 packets at t = [0, 1, 2, 3, 5, 7, 10] s + 0–250 ms random jitter; steady-state announce is 57 s + 0–6 s random. mDNS service equivalents: _musc._tcp, _muss._tcp, _musp._tcp, _musz._tcp, _mush._tcp, _remote-web-ui._tcp. LSDP is included here for completeness; it is not in the protocols: list and not enumerated as an action.

Input-selection firmware split. The source explicitly documents two different Play?inputIndex= and Play?inputTypeIndex= shapes depending on firmware:

  • Firmware newer than v3.8.0 and older than v4.2.0: /Play?inputIndex=N
  • Firmware v4.2.0 or newer: /Play?inputTypeIndex={type}-{index}

The spec lists both as separate actions (input_external_legacy, input_external_typed); clients should detect firmware and pick the right one.

Preset ids are not sequential. The source notes preset numbers may be 1, 2, 3, 5, 7, 8 with gaps; ids are returned by /Presets and used with /Preset?id=. Use /Preset?id=+1 and /Preset?id=-1 to step.

Source document. The source is the BluOS Custom Integration API reference (vendor manual). It documents the protocol generically — not a single product model — and applies to every BluOS-based Bluesound, NAD, and DALI player. The "SiriusXM" tag in the family name reflects SiriusXM being one of the available streaming services on these players, not a SiriusXM-specific control surface.

Provenance

source_domains:
  - bluesoundprofessional.com
  - content-bluesound-com.s3.amazonaws.com
source_urls:
  - https://bluesoundprofessional.com/wp-content/uploads/2025/06/BluOS-Custom-Integration-API_v1.7.pdf
  - https://content-bluesound-com.s3.amazonaws.com/uploads/2022/04/Custom-Integration-API-v1.4.pdf
retrieved_at: 2026-06-01T22:01:09.682Z
last_checked_at: 2026-06-02T08:27:28.483Z

Verification Summary

verdict: verified
checked_at: 2026-06-02T08:27:28.483Z
matched_actions: 49
action_count: 49
confidence: medium
summary: "All 49 spec actions have verbatim command-level matches in the BluOS Custom Integration API source; transport port 11000 and auth:none are confirmed; source catalogue is fully covered. (9 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "SiriusXM-specific playback endpoints (e.g. station, preset, like/ban actions unique to SiriusXM) are not isolated in the source — they are served by the generic BluOS /Play, /Preset, /Action, /Browse, and /Shuffle endpoints below."
- "no continuous settable parameters beyond the discrete actions above."
- "whether the device pushes any unsolicited HTTP/SSE/UDP events"
- "the source does not describe device-side multi-step macros."
- "source contains no safety warnings, interlocks, or power-on sequencing"
- "firmware version compatibility ranges for individual endpoints are not stated per-endpoint; only the input-selection endpoints have explicit firmware cutovers (v3.8.0, v4.2.0)."
- "voltage, current, power consumption, and physical-layer electrical specs are not in this source."
- "whether `Authorization`, session, or other auth is required for any endpoint — the source shows none and the inference is `auth.type: none`."
- "whether the device accepts concurrent /Play from multiple clients and how it arbitrates last-writer-wins."

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