Summary
BluOS is a multi-room networked audio operating system found on Bluesound, NAD Electronics, DALI Loudspeakers and other products. This spec covers the Custom Integration (CI) HTTP API used to query status, control volume and playback, manage the play queue, browse music services, group players, change inputs, reboot the device, and trigger doorbell chimes. All requests are HTTP GET to http://<player_ip>:<port>/<request>, with responses as UTF-8 encoded XML.
Transport
protocols:
- http
addressing:
port: 11000
base_url: http://<player_ip>:11000
auth:
type: none # inferred: no auth procedure in source
Traits
- powerable # inferred: reboot/soft-reboot endpoint present
- routable # inferred: input selection and play queue management endpoints present
- queryable # inferred: /Status, /SyncStatus, /Playlist, /Presets query endpoints
- levelable # inferred: volume up/down/set/mute endpoints present
Actions
# Status queries
- id: status_query
label: Playback Status Query
kind: query
command: "GET /Status"
params:
- name: timeout
type: integer
description: Optional long-polling timeout in seconds (recommended 100, min 10)
- name: etag
type: string
description: Optional etag value from previous /Status response for long polling
- id: sync_status_query
label: Player and Group Sync Status Query
kind: query
command: "GET /SyncStatus"
params:
- name: timeout
type: integer
description: Optional long-polling timeout in seconds (recommended 180)
- name: etag
type: string
description: Optional etag value from previous /SyncStatus response
# Volume control
- id: set_volume_level
label: Set Volume (0..100)
kind: action
command: "GET /Volume?level={level}&tell_slaves={tell_slaves}"
params:
- name: level
type: integer
description: Absolute volume level 0-100
- name: tell_slaves
type: integer
description: 0=player only, 1=also apply to group slaves
- id: set_volume_abs_db
label: Set Volume (absolute dB)
kind: action
command: "GET /Volume?abs_db={abs_db}&tell_slaves={tell_slaves}"
params:
- name: abs_db
type: number
description: Absolute volume in dB
- name: tell_slaves
type: integer
description: 0=player only, 1=also apply to group slaves
- id: set_volume_relative_db
label: Adjust Volume (relative dB)
kind: action
command: "GET /Volume?db={delta_db}&tell_slaves={tell_slaves}"
params:
- name: delta_db
type: number
description: Relative volume change in dB (positive or negative)
- name: tell_slaves
type: integer
description: 0=player only, 1=also apply to group slaves
- id: volume_up
label: Volume Up
kind: action
command: "GET /Volume?db=2"
params: []
- id: volume_down
label: Volume Down
kind: action
command: "GET /Volume?db=-2"
params: []
- 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
kind: action
command: "GET /Play"
params: []
- id: play_seek
label: Play with Seek
kind: action
command: "GET /Play?seek={seconds}"
params:
- name: seconds
type: integer
description: Seconds to seek into current track
- id: play_seek_track
label: Play Track at Seek Position
kind: action
command: "GET /Play?seek={seconds}&id={trackid}"
params:
- name: seconds
type: integer
description: Seconds to seek into track
- name: trackid
type: integer
description: Track id in queue
- id: play_url
label: Play Stream URL
kind: action
command: "GET /Play?url={encodedStreamURL}"
params:
- name: encodedStreamURL
type: string
description: URL-encoded stream URL
- 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: []
- id: back
label: Skip Previous Track
kind: action
command: "GET /Back"
params: []
- id: shuffle
label: Set Shuffle
kind: action
command: "GET /Shuffle?state={state}"
params:
- name: state
type: integer
description: 0=disable, 1=enable
- id: repeat
label: Set Repeat
kind: action
command: "GET /Repeat?state={state}"
params:
- name: state
type: integer
description: 0=repeat queue, 1=repeat track, 2=off
# Streaming radio actions
- id: action_skip
label: Streaming Radio Skip
kind: action
command: "GET /Action?service={service-name}&{action-URL}"
params:
- name: service-name
type: string
description: Music service name
- name: action-URL
type: string
description: URL from <action url="..."> element in /Status response
- id: action_love
label: Streaming Radio Love Track
kind: action
command: "GET /Action?service={service-name}&{action-URL}"
params:
- name: service-name
type: string
description: Music service name
- name: action-URL
type: string
description: Love URL from <action> element
- id: action_ban
label: Streaming Radio Ban Track
kind: action
command: "GET /Action?service={service-name}&{action-URL}"
params:
- name: service-name
type: string
description: Music service name
- name: action-URL
type: string
description: Ban URL from <action> element
# Play queue management
- id: list_playlist
label: List Play Queue
kind: query
command: "GET /Playlist"
params: []
- id: list_playlist_status
label: Play Queue Status
kind: query
command: "GET /Playlist?length=1"
params: []
- id: list_playlist_paginated
label: List Play Queue (Paginated)
kind: query
command: "GET /Playlist?start={first}&end={last}"
params:
- name: first
type: integer
description: First queue index (starts from 0)
- name: last
type: integer
description: Last queue index
- id: delete_track
label: Delete Track from Queue
kind: action
command: "GET /Delete?id={position}"
params:
- name: position
type: integer
description: Position in queue
- id: move_track
label: Move Track in Queue
kind: action
command: "GET /Move?new={destination}&old={origin}"
params:
- name: destination
type: integer
description: New position
- name: origin
type: integer
description: Old position
- id: clear_queue
label: Clear Play Queue
kind: action
command: "GET /Clear"
params: []
- id: save_queue
label: Save Play Queue as Playlist
kind: action
command: "GET /Save?name={playlist_name}"
params:
- name: playlist_name
type: string
description: Name for the saved playlist
# Presets
- id: list_presets
label: List Presets
kind: query
command: "GET /Presets"
params: []
- id: load_preset
label: Load Preset by ID
kind: action
command: "GET /Preset?id={presetId}"
params:
- name: presetId
type: integer
description: Preset ID number
- id: load_next_preset
label: Load Next Preset
kind: action
command: "GET /Preset?id=+1"
params: []
- id: load_previous_preset
label: Load Previous Preset
kind: action
command: "GET /Preset?id=-1"
params: []
# Content browsing and search
- id: browse_root
label: Browse Root
kind: query
command: "GET /Browse"
params: []
- id: browse_key
label: Browse by Key
kind: query
command: "GET /Browse?key={key-value}"
params:
- name: key-value
type: string
description: URL-encoded browseKey/nextKey/parentKey/contextMenuKey
- id: browse_key_with_context
label: Browse by Key with Context Menu
kind: query
command: "GET /Browse?key={key-value}&withContextMenuItems=1"
params:
- name: key-value
type: string
description: URL-encoded key value
- name: withContextMenuItems
type: integer
description: Always 1
- id: search_content
label: Search Music Content
kind: query
command: "GET /Browse?key={key-value}&q={searchText}"
params:
- name: key-value
type: string
description: searchKey from prior response (URL-encoded)
- name: searchText
type: string
description: Search string
# Player grouping
- id: group_one_slave
label: Group One Slave to Primary
kind: action
command: "GET /AddSlave?slave={secondaryPlayerIP}&port={secondaryPlayerPort}&group={GroupName}"
params:
- name: secondaryPlayerIP
type: string
description: IP address of secondary player
- name: secondaryPlayerPort
type: integer
description: Port number of secondary player (default 11000)
- name: GroupName
type: string
description: Optional group name
- id: group_multiple_slaves
label: Group Multiple Slaves to Primary
kind: action
command: "GET /AddSlave?slaves={secondaryPlayerIPs}&ports={secondaryPlayerPorts}"
params:
- name: secondaryPlayerIPs
type: string
description: Comma-separated secondary player IP addresses
- name: secondaryPlayerPorts
type: string
description: Comma-separated secondary player ports
- id: ungroup_one_slave
label: Remove One Player From Group
kind: action
command: "GET /RemoveSlave?slave={secondaryPlayerIP}&port={secondaryPlayerPort}"
params:
- name: secondaryPlayerIP
type: string
description: IP of secondary player to ungroup
- name: secondaryPlayerPort
type: integer
description: Port of secondary player to ungroup
- id: ungroup_multiple_slaves
label: Remove Multiple Players From Group
kind: action
command: "GET /RemoveSlave?slaves={secondaryPlayerIPs}&ports={secondaryPlayerPorts}"
params:
- name: secondaryPlayerIPs
type: string
description: Comma-separated secondary player IP addresses
- name: secondaryPlayerPorts
type: string
description: Comma-separated secondary player ports
# Player reboot
- id: reboot_player
label: Reboot Player
kind: action
command: "POST /reboot (body: yes=1)"
params: []
# Doorbell
- id: play_doorbell
label: Play Doorbell Chime
kind: action
command: "GET /Doorbell?play=1"
params: []
# Direct input selection
- id: active_input_select
label: Active Input Selection
kind: action
command: "GET /Play?url={URL_value}"
params:
- name: URL_value
type: string
description: URL attribute from /RadioBrowse?service=Capture response
- id: external_input_select_legacy
label: External Input Selection (firmware >v3.8.0, <v4.2.0)
kind: action
command: "GET /Play?inputIndex={IndexId}"
params:
- name: IndexId
type: integer
description: Index from /Settings?id=capture response (Bluetooth excluded, starts at 1)
- id: external_input_select_typed
label: External Input Selection (firmware >=v4.2.0)
kind: action
command: "GET /Play?inputTypeIndex={typeIndex}"
params:
- name: typeIndex
type: string
description: Format type-index, e.g. spdif-2, analog-1, bluetooth-1, arc-1, earc-1, phono-1, coax-1, computer-1, aesebu-1, balanced-1, microphone-1
# Bluetooth mode
- id: set_bluetooth_mode
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
Feedbacks
# /Status feedback (per-response fields)
- id: status_state
type: enum
values: [play, pause, stop, stream, connecting]
description: Current player state from /Status <state>
- id: status_volume
type: integer
description: Volume level 0-100 (-1 means fixed volume)
- id: status_db
type: number
description: Volume in dB
- id: status_mute
type: enum
values: [0, 1]
description: Mute state (1=muted)
- id: status_mute_db
type: number
description: Unmuted dB volume when muted
- id: status_mute_volume
type: integer
description: Unmuted 0-100 volume when muted
- id: status_shuffle
type: enum
values: [0, 1]
description: Shuffle state
- id: status_repeat
type: enum
values: [0, 1, 2]
description: Repeat state (0=queue, 1=track, 2=off)
- id: status_song
type: integer
description: Current track position in queue
- id: status_totlen
type: integer
description: Total track length in seconds
- id: status_secs
type: integer
description: Seconds played in current track
- id: status_can_seek
type: enum
values: [0, 1]
description: Whether seek is supported on current track
- id: status_can_move_playback
type: boolean
description: Whether playback can be moved to another player
- id: status_album
type: string
description: Album of current track
- id: status_artist
type: string
description: Artist of current track
- id: status_title1
type: string
description: First metadata line
- id: status_title2
type: string
description: Second metadata line
- id: status_title3
type: string
description: Third metadata line
- id: status_service
type: string
description: Music service id
- id: status_quality
type: string
description: Audio quality (cd/hd/dolbyAudio/mqa/mqaAuthored/numeric bitrate)
- id: status_stream_url
type: string
description: Presence indicates play queue is not source of audio
- id: status_sleep
type: integer
description: Minutes remaining before sleep timer
- id: status_indexing
type: enum
values: [0, 1]
description: Indexing in progress flag
# /SyncStatus feedback
- id: sync_status_etag
type: string
description: Etag for long polling
- id: sync_status_group
type: string
description: Group name
- id: sync_status_volume
type: integer
description: Volume level 0-100
- id: sync_status_mute
type: enum
values: [0, 1]
description: Mute state
- id: sync_status_initialized
type: boolean
description: Whether player has been set up
- id: sync_status_schema_version
type: integer
description: Software schema version
- id: sync_status_mac
type: string
description: Player MAC address
- id: sync_status_brand
type: string
description: Player brand name
- id: sync_status_model
type: string
description: Player model id
- id: sync_status_model_name
type: string
description: Player model name
- id: sync_status_name
type: string
description: Player name
# /Volume feedback
- id: volume_response_etag
type: string
description: Etag of volume response
# /Playlist feedback
- id: playlist_id
type: integer
description: Unique id for current queue state
- id: playlist_length
type: integer
description: Total number of tracks in queue
- id: playlist_modified
type: enum
values: [0, 1]
description: 1=queue modified since loaded
# /Presets feedback
- id: presets_prid
type: integer
description: Unique id for player presets
Variables
# UNRESOLVED: no continuous setable variables beyond Volume (covered as actions above)
Events
# UNRESOLVED: source describes responses to commands but no unsolicited notification mechanism beyond long-polling /Status and /SyncStatus
Macros
# UNRESOLVED: source does not document multi-step macro sequences; macros can be composed client-side from the actions above
Safety
confirmation_required_for:
- context_menu_delete # inferred: source notes user confirmation should be requested for delete context menu items
interlocks: []
# UNRESOLVED: source does not document power-on sequencing, fault behavior, or hardware interlocks
Notes
- Port 11000 used for all BluOS players except CI580 (which uses 11000/11010/11020/11030 for nodes 1-4).
- mDNS services
musc.tcpandmusp.tcpshould be used to discover players and their ports. - Long-polling pattern:
/Statusand/SyncStatusaccepttimeoutandetagquery params. Recommended polling interval is at most one request every 30 seconds when not using long polling. For long polling: /Status recommended 100s (60s+), /SyncStatus recommended 180s. No two consecutive long-poll requests for the same resource within one second. - /Status covers playback state; /SyncStatus covers player/group identity and volume. Use
syncStatelement to detect changes. - /Pause and /Stop cancel alarm timeouts when an alarm is playing.
- /Preset id accepts "+1" and "-1" for next/previous preset. Presets loop top-to-bottom and bottom-to-top.
- /Shuffle retains original queue for restore when disabled.
- Section 11.2 documents two firmware-dependent input selection paths:
inputIndexfor firmware between v3.8.0 and v4.2.0, andinputTypeIndexfor v4.2.0+. Bluetooth excluded from inputIndex enumeration; spdif/analog/coax/bluetooth/arc/earc/phono/computer/aesebu/balanced/microphone are valid type names for inputTypeIndex. - LSDP (Lenbrook Service Discovery Protocol) uses UDP broadcast to/from port 11430. Magic word "LSDP" (4 ASCII bytes), current protocol version 1.
- 7 startup packets sent at absolute times [0, 1, 2, 3, 5, 7, 10s] + 0-250ms random jitter; main announce period 57s + 0-6s random; query response delay 0-750ms random.
Provenance
source_domains:
- bluos.io
source_urls:
- https://bluos.io/wp-content/uploads/2025/06/BluOS-Custom-Integration-API_v1.7.pdf
retrieved_at: 2026-07-12T08:15:31.069Z
last_checked_at: 2026-09-03T22:16:31.392Z
Verification Summary
verdict: verified
checked_at: 2026-09-03T22:16:31.392Z
matched_actions: 48
action_count: 48
confidence: medium
summary: "All 48 spec actions match documented BluOS CI API endpoints; transport port 11000 verified verbatim; bidirectional coverage of the source's stated subset is complete. (6 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "full LSDP discovery packet structure (Query/Announce/Delete message blocks beyond header) is referenced but not fully reproduced in source"
- "no continuous setable variables beyond Volume (covered as actions above)"
- "source describes responses to commands but no unsolicited notification mechanism beyond long-polling /Status and /SyncStatus"
- "source does not document multi-step macro sequences; macros can be composed client-side from the actions above"
- "source does not document power-on sequencing, fault behavior, or hardware interlocks"
- "LSDP Announce/Delete message block byte layouts not reproduced in source chunk 2; protocol overview referenced but block details beyond header absent."
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0