Summary
BluOS network media player running the BluOS operating system. This spec covers the Custom Integration (CI) HTTP API: all requests sent as HTTP GET to http://<player_ip>:<port>/<request>, responses returned as UTF-8 encoded XML. Covers playback, volume, queue, presets, content browsing, player grouping, reboot, doorbell chime, and input selection.
Transport
protocols:
- http
addressing:
base_url: http://<player_ip>:<port>
port: 11000
auth:
type: none # inferred: no auth procedure in source
Notes on addressing:
- Default port 11000 for all BluOS players. Exception: NAD CI580 chassis uses four streamer nodes on one IP — node 1 port 11000, node 2 port 11010, node 3 port 11020, node 4 port 11030.
- Actual port should be discovered via MDNS using services
musc.tcpandmusp.tcp. - All requests are HTTP GET (one exception:
/rebootis POST). Parameters are URL-encoded name/value pairs. Responses are UTF-8 XML. - Example base used throughout source:
http://192.168.1.100:11000.
Traits
traits:
- queryable # inferred from /Status, /SyncStatus, /Playlist, /Presets, /Volume query examples
- levelable # inferred from /Volume level/db/abs_db commands
Actions
actions:
# --- Status Queries (Section 2) ---
- id: status_query
label: Playback Status Query
kind: query
command: "GET /Status"
params:
- name: timeout
type: integer
description: Optional long-poll timeout in seconds. Recommended 100; never faster than 10.
- name: etag
type: string
description: Optional etag from previous /Status response, used 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-poll interval in seconds. Recommended 180.
- name: etag
type: string
description: Optional etag from previous /SyncStatus response.
# --- Volume Control (Section 3) ---
- id: volume_set_level
label: Set Volume (Level)
kind: action
command: "GET /Volume?level={level}&tell_slaves={tell_slaves}"
params:
- name: level
type: integer
description: Absolute volume level, integer 0..100.
- name: tell_slaves
type: integer
description: Grouped players. 0 = only selected player changes; 1 = all group players change.
- id: volume_set_absolute_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 on dB scale (range typically -80..0).
- name: tell_slaves
type: integer
description: 0 = only selected player; 1 = all group players.
- id: volume_change_relative_db
label: Volume Change (Relative dB)
kind: action
command: "GET /Volume?db={db}&tell_slaves={tell_slaves}"
params:
- name: db
type: number
description: Relative dB change; positive = up, negative = down. Typical step 2 or -2.
- name: tell_slaves
type: integer
description: 0 = only selected player; 1 = all group players.
- id: volume_mute_set
label: Set Mute State
kind: action
command: "GET /Volume?mute={mute}&tell_slaves={tell_slaves}"
params:
- name: mute
type: integer
description: 0 = unmute (per source's /Volume?mute= parameter convention); 1 = mute.
- name: tell_slaves
type: integer
description: 0 = only selected player; 1 = all group players.
- 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 (Section 4) ---
- id: play
label: Play
kind: action
command: "GET /Play"
params: []
- id: play_seek
label: Play at Seek Position
kind: action
command: "GET /Play?seek={seek}"
params:
- name: seek
type: integer
description: Jump to position in seconds within current track. Requires /Status <totlen>. Cannot combine with inputType/index.
- id: play_seek_id
label: Play at Seek Position in Specific Track
kind: action
command: "GET /Play?seek={seek}&id={id}"
params:
- name: seek
type: integer
description: Position in seconds within the track.
- name: id
type: integer
description: Track id in the play queue (0-based).
- id: play_url
label: Play URL / Stream
kind: action
command: "GET /Play?url={url}"
params:
- name: url
type: string
description: URL-encoded stream URL to play.
- 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 to Next Track
kind: action
command: "GET /Skip"
params: []
- id: back
label: Back to Previous Track / Start
kind: action
command: "GET /Back"
params: []
- id: shuffle_set
label: Set Shuffle
kind: action
command: "GET /Shuffle?state={state}"
params:
- name: state
type: integer
description: 0 = shuffle off; 1 = shuffle on.
- id: repeat_set
label: Set Repeat
kind: action
command: "GET /Repeat?state={state}"
params:
- name: state
type: integer
description: 0 = repeat queue; 1 = repeat track; 2 = repeat off.
- id: action_streaming_radio
label: Streaming Radio Action (skip/back/love/ban)
kind: action
command: "GET /Action?service={service}&{action_param}={action_value}"
params:
- name: service
type: string
description: Service name (e.g. Slacker). Taken from /Status <service> or <action> element.
- name: action_param
type: string
description: One of skip, back, love, ban. The URL/value comes from <action> element in /Status response.
- name: action_value
type: string
description: Action-specific value from the <action> url attribute.
# --- Play Queue Management (Section 5) ---
- id: playlist_list
label: List Play Queue
kind: query
command: "GET /Playlist"
params: []
- id: playlist_list_status
label: List Play Queue Status Only
kind: query
command: "GET /Playlist?length=1"
params: []
- id: playlist_list_range
label: List Play Queue Range
kind: query
command: "GET /Playlist?start={start}&end={end}"
params:
- name: start
type: integer
description: First queue entry to include (0-based).
- name: end
type: integer
description: Last queue entry to include.
- id: delete_track
label: Delete Track
kind: action
command: "GET /Delete?id={id}"
params:
- name: id
type: integer
description: Track id (queue position) to remove.
- id: move_track
label: Move Track
kind: action
command: "GET /Move?new={new}&old={old}"
params:
- name: new
type: integer
description: New position of the track being moved.
- name: old
type: integer
description: Old position of the track being moved.
- id: clear_queue
label: Clear Play Queue
kind: action
command: "GET /Clear"
params: []
- id: save_queue
label: Save Queue as Playlist
kind: action
command: "GET /Save?name={name}"
params:
- name: name
type: string
description: Name to save the play queue under (URL-encoded).
# --- Presets (Section 6) ---
- id: list_presets
label: List Presets
kind: query
command: "GET /Presets"
params: []
- id: load_preset
label: Load Preset
kind: action
command: "GET /Preset?id={id}"
params:
- name: id
type: string
description: Preset id, or +1 for next preset, or -1 for previous preset.
# --- Content Browsing and Searching (Section 7) ---
- id: browse_top
label: Top-Level Browse
kind: query
command: "GET /Browse"
params: []
- id: browse_key
label: Browse by Key
kind: query
command: "GET /Browse?key={key}"
params:
- name: key
type: string
description: URL-encoded key from browseKey / nextKey / parentKey / contextMenuKey of prior response. Omit for top-level.
- id: browse_with_context_menu
label: Browse with Inline Context Menu
kind: query
command: "GET /Browse?key={key}&withContextMenuItems=1"
params:
- name: key
type: string
description: URL-encoded browse key.
- id: search
label: Search Music Content
kind: query
command: "GET /Browse?key={key}&q={q}"
params:
- name: key
type: string
description: URL-encoded searchKey from prior response. May be omitted for top-level search.
- name: q
type: string
description: URL-encoded search string.
# --- Player Grouping (Section 8) ---
- id: group_one_player
label: Group One Player (Add Slave)
kind: action
command: "GET /AddSlave?slave={slave}&port={port}&group={group}"
params:
- name: slave
type: string
description: IP address of the secondary player.
- name: port
type: integer
description: Port of the secondary player. Default 11000.
- name: group
type: string
description: OPTIONAL group name. If omitted BluOS assigns a default name.
- id: group_multiple_players
label: Group Multiple Players (Add Slaves)
kind: action
command: "GET /AddSlave?slaves={slaves}&ports={ports}"
params:
- name: slaves
type: string
description: Comma-separated IP addresses of secondary players.
- name: ports
type: string
description: Comma-separated port numbers of secondary players.
- id: remove_one_player
label: Remove One Player From Group
kind: action
command: "GET /RemoveSlave?slave={slave}&port={port}"
params:
- name: slave
type: string
description: IP address of the player to remove.
- name: port
type: integer
description: Port of the player to remove.
- id: remove_multiple_players
label: Remove Multiple Players From Group
kind: action
command: "GET /RemoveSlave?slaves={slaves}&ports={ports}"
params:
- name: slaves
type: string
description: Comma-separated IP addresses of secondary players to remove.
- name: ports
type: string
description: Comma-separated port numbers.
# --- Player Reboot (Section 9) ---
- id: reboot
label: Soft Reboot Player
kind: action
command: "POST /reboot"
params:
- name: yes
type: string
description: Confirmation value (any value, e.g. 1). Sent as POST body (curl example: curl -d yes=1).
# --- Doorbell Chimes (Section 10) ---
- id: doorbell
label: Doorbell Chime
kind: action
command: "GET /Doorbell?play=1"
params: []
# --- Direct Input Selection (Section 11) ---
- id: play_active_input
label: Select Active Input by URL
kind: action
command: "GET /Play?url={url}"
params:
- name: url
type: string
description: URL attribute from /RadioBrowse?service=Capture response (URL-encoded).
- id: play_external_input_index
label: Select External Input by Index
kind: action
command: "GET /Play?inputIndex={inputIndex}"
params:
- name: inputIndex
type: integer
description: 1-based index of inputs from /Settings?id=capture&schemaVersion=32 in numerical order. Bluetooth excluded. (BluOS firmware newer than v3.8.0 and older than v4.2.0.)
- id: radiobrowse_capture
label: List Capture Inputs (RadioBrowse)
kind: query
command: "GET /RadioBrowse?service=Capture"
params: []
- id: settings_capture
label: Get Capture Settings
kind: query
command: "GET /Settings?id=capture&schemaVersion=32"
params: []
Feedbacks
feedbacks:
- id: volume_state
type: object
description: Volume response from /Volume. Fields include db (dB level), mute (0/1), offsetDb, etag, body text = level 0..100 or -1 for fixed volume. Also muteDb / muteVolume when muted.
source: /Volume response
- id: playback_status
type: object
description: Full /Status response. Many attributes including state (play/pause/stop/stream/connecting), volume, shuffle, repeat, secs, totlen, title1/title2/title3, artist, album, name, image, quality, streamFormat, pid, prid, syncStat, etag, canSeek, etc.
source: /Status response
- id: sync_status
type: object
description: Full /SyncStatus response. Player attributes including volume, modelName, name, model, brand, etag, id, mac, group, syncStat, master (if secondary), slave(s) (if primary), zone info, battery info.
source: /SyncStatus response
- id: play_state
type: enum
values: [play, pause, stop, stream, connecting]
description: State element returned by /Play, /Pause, /Stop. play and stream should be treated as equivalent.
- id: shuffle_state
type: enum
values: ["0", "1"]
description: Shuffle state. 0 = off, 1 = on. Returned by /Shuffle and in /Status <shuffle>.
- id: repeat_state
type: enum
values: ["0", "1", "2"]
description: Repeat state. 0 = repeat queue, 1 = repeat track, 2 = repeat off. Returned by /Repeat and in /Status <repeat>.
- id: presets_list
type: object
description: /Presets response. Each preset has id, name, url, image. Root has prid.
- id: playlist_state
type: object
description: /Playlist response. Attributes name, modified, length, id; song entries when listing.
Variables
variables:
- id: volume_level
type: integer
range: [-1, 0, 100]
description: Player volume 0..100; -1 means fixed volume. Set via /Volume?level=.
- id: volume_db
type: number
description: Volume in dB. Typically -80..0. Set via /Volume?abs_db=.
- id: mute
type: integer
enum: [0, 1]
description: 0 = unmuted, 1 = muted. Set via /Volume?mute=.
- id: shuffle
type: integer
enum: [0, 1]
description: 0 = off, 1 = on. Set via /Shuffle?state=.
- id: repeat
type: integer
enum: [0, 1, 2]
description: 0 = repeat queue, 1 = repeat track, 2 = off. Set via /Repeat?state=.
Events
# No unsolicited notifications documented in source. All responses are solicited (HTTP request → response).
# Long-polling via /Status and /SyncStatus with etag/timeout is the closest mechanism to event delivery.
# UNRESOLVED: no push/websocket/sse mechanism described.
Macros
# No explicit multi-step sequences documented as macros. Input selection workflows
# (Section 11.1 / 11.2) describe a 2-step sequence (query inputs → /Play?url= or /Play?inputIndex=)
# but these are presented as caller-side orchestration, not device-side macros.
# UNRESOLVED: no device-side macros described in source.
Safety
confirmation_required_for: []
interlocks: []
# UNRESOLVED: source contains no explicit safety warnings, interlock procedures, or power-on
# sequencing requirements. /reboot is a soft reboot that disconnects the player (response:
# "Rebooting. Please close this window.") - caller-side confirmation recommended but not
# specified by vendor. /Doorbell pre-empts current audio (implied) but no interlock stated.
Notes
- Transport nuance: Source calls it "TCP/IP" / "HTTP" interchangeably. Strictly, all requests are HTTP GET except
/rebootwhich is POST. Underlying transport is TCP. Spec useshttpas the protocol identifier since that is the application layer the API defines. - Port discovery: Use MDNS services
musc.tcpandmusp.tcpto discover the actual port. 11000 is the documented default for single-node players; CI580 uses 11000/11010/11020/11030 for its four nodes. - Long polling: Both
/Statusand/SyncStatussupport long polling viatimeout+etagquery params. When not long-polling, clients must limit to ≤1 request per 30 seconds per resource. When long-polling, ≥1 second between consecutive requests for the same resource. - Grouping semantics: Primary player = group source selector. Secondary players proxy many requests (Status, Playback, Queue, Browse) to the primary internally. To track individual secondary volume, poll each secondary's
/SyncStatus. tell_slavessemantics: Only meaningful for grouped players. 0 = selected player only, 1 = all players in group.- Volume range: Configurable via BluOS Controller app (Settings → Player → Audio). Typically -80..0 dB.
- Mute parameter convention: Source's
/Volume?mute=description says "If set to 0, the player is muted. If set to 1, the player is unmuted" (section 3.1 table) — this is INVERTED relative to sections 3.4 (/Volume?mute=1= Mute On) and 3.5 (/Volume?mute=0= Mute Off), as well as inverted relative to every<mute>response attribute (1 = muted). The 3.1 parameter description appears to be a documentation error; sections 3.4/3.5 and the response attribute convention are authoritative:mute=1mutes,mute=0unmutes. - Input selection variants: Section 11.1 (
/Play?url=from/RadioBrowse?service=Capture) covers active inputs and HUB inputs. Section 11.2 (/Play?inputIndex=) covers external inputs (active or inactive) and is recommended for CI; firmware-bound to >v3.8.0 and <v4.2.0 per source. A v4.2.0+ variant is implied but not documented. /Play?url=overloaded: Same endpoint used for streaming a custom URL (section 4.1) and for active input selection (section 11.1) — caller context determines intent.- Browse key encoding: All
key,browseKey,contextMenuKey,searchKeyvalues must be percent-encoded when used as thekeyparameter. URIs are relative with absolute path and resolved per RFC 3986.
## Provenance
```yaml
source_domains:
- bluos.io
source_urls:
- https://bluos.io/wp-content/uploads/2025/06/BluOS-Custom-Integration-API_v1.7.pdf
retrieved_at: 2026-08-10T20:30:44.027Z
last_checked_at: 2026-08-19T09:00:14.357Z
```
## Verification Summary
```yaml
verdict: verified
checked_at: 2026-08-19T09:00:14.357Z
matched_actions: 43
action_count: 43
confidence: medium
summary: "All 43 spec actions match documented BluOS CI API endpoints verbatim; transport port and base URL match the source's HTTP convention. (13 unresolved item(s) noted in Known Gaps.)"
```
## Known Gaps
```yaml
- "source document is the generic BluOS CI API v1.7 — does not state which specific hardware models (other than example PULSE P300) implement it. \"BluOS Bluray Player\" used as device name per task input; model coverage not confirmed against device list."
- "firmware version compatibility range not stated (one sub-feature references firmware v3.8.0 and v4.2.0 boundaries only)."
- "protocol version (MDNS service discovery via musc.tcp / musp.tcp referenced but discovery details not specified)."
- "MDNS discovery details (TXT records, service instance naming) not specified beyond service names."
- "no push/websocket/sse mechanism described."
- "no device-side macros described in source."
- "source contains no explicit safety warnings, interlock procedures, or power-on"
- "model coverage — source is generic BluOS CI API; not confirmed which exact models implement every command. \"BluOS Bluray Player\" used as device name from task input."
- "schemaVersion — /SyncStatus returns schemaVersion attribute (e.g. \"25\"); /Settings examples reference schemaVersion=32 as \"the latest schema version\". Version-to-feature mapping not documented."
- "firmware version → command availability table not provided (only the inputIndex boundary noted)."
- "no explicit error code / fault response catalogue. /Browse may return <error><message/><detail/></error> but no enumeration of error codes."
- "MDNS TXT record contents not specified."
- "BluOS HUB fixed grouping commands referenced as \"out of scope for this document\" — not covered."
```
---
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0