Skip to content
Navigation API Reference

Navigation API Reference

Navigation API Reference

Overview

This document provides a complete API reference for the Bose SoundTouch navigation and station management functionality. For usage examples and workflows, see NAVIGATION-GUIDE.md.

Table of Contents

Client Methods

Navigation Methods

Navigate(source, sourceAccount string, startItem, numItems int) (*models.NavigateResponse, error)

Browse content within a source.

Parameters:

  • source (string, required): Content source identifier
    • Valid values: "TUNEIN", "PANDORA", "SPOTIFY", "STORED_MUSIC", "BLUETOOTH", "AUX"
  • sourceAccount (string, optional): Account identifier for authenticated sources
  • startItem (int, required): Starting position (1-based index)
  • numItems (int, required): Number of items to retrieve

Returns:

  • *models.NavigateResponse: Navigation results with items and metadata
  • error: Error if request fails

Example:

response, err := client.Navigate("TUNEIN", "", 1, 25)

Validation:

  • source cannot be empty
  • startItem must be >= 1
  • numItems must be >= 1

NavigateWithMenu(source, sourceAccount, menu, sort string, startItem, numItems int) (*models.NavigateResponse, error)

Browse content with specific menu and sorting options (primarily for Pandora).

Parameters:

  • source (string, required): Content source identifier
  • sourceAccount (string, optional): Account identifier
  • menu (string, optional): Menu context (e.g., "radioStations")
  • sort (string, optional): Sort order (e.g., "dateCreated")
  • startItem (int, required): Starting position (1-based)
  • numItems (int, required): Number of items to retrieve

Returns:

  • *models.NavigateResponse: Navigation results
  • error: Error if request fails

Example:

response, err := client.NavigateWithMenu("PANDORA", "user123", "radioStations", "dateCreated", 1, 100)

NavigateContainer(source, sourceAccount string, startItem, numItems int, containerItem *models.ContentItem) (*models.NavigateResponse, error)

Browse into a specific container/directory.

Parameters:

  • source (string, required): Content source identifier
  • sourceAccount (string, optional): Account identifier
  • startItem (int, required): Starting position (1-based)
  • numItems (int, required): Number of items to retrieve
  • containerItem (*models.ContentItem, required): Container to browse into

Returns:

  • *models.NavigateResponse: Container contents
  • error: Error if request fails

Example:

response, err := client.NavigateContainer("STORED_MUSIC", "device/0", 1, 100, albumContentItem)

Validation:

  • containerItem cannot be nil
  • Container must have valid Location field

Convenience Navigation Methods

GetTuneInStations(sourceAccount string) (*models.NavigateResponse, error)

Browse TuneIn radio stations.

Parameters:

  • sourceAccount (string, optional): TuneIn account (usually empty)

Returns:

  • *models.NavigateResponse: TuneIn stations and content

Example:

stations, err := client.GetTuneInStations("")

GetPandoraStations(sourceAccount string) (*models.NavigateResponse, error)

Browse Pandora radio stations with proper sorting.

Parameters:

  • sourceAccount (string, required): Pandora user account identifier

Returns:

  • *models.NavigateResponse: Pandora stations sorted by creation date

Example:

stations, err := client.GetPandoraStations("user123")

Validation:

  • sourceAccount cannot be empty

GetStoredMusicLibrary(sourceAccount string) (*models.NavigateResponse, error)

Browse stored/local music library.

Parameters:

  • sourceAccount (string, required): Device account identifier (format: deviceID/index)

Returns:

  • *models.NavigateResponse: Music library root contents

Example:

library, err := client.GetStoredMusicLibrary("AABBCCDDEEFF/0")

Validation:

  • sourceAccount cannot be empty

Search Methods

SearchStation(source, sourceAccount, searchTerm string) (*models.SearchStationResponse, error)

Search for stations and content within a music service.

Parameters:

  • source (string, required): Service to search
  • sourceAccount (string, optional): Account identifier
  • searchTerm (string, required): Search query

Returns:

  • *models.SearchStationResponse: Search results categorized by type
  • error: Error if request fails

Example:

results, err := client.SearchStation("PANDORA", "user123", "jazz")

Validation:

  • source cannot be empty
  • searchTerm cannot be empty

SearchTuneInStations(searchTerm string) (*models.SearchStationResponse, error)

Search TuneIn radio stations.

Parameters:

  • searchTerm (string, required): Search query

Returns:

  • *models.SearchStationResponse: TuneIn search results

Example:

results, err := client.SearchTuneInStations("classical music")

SearchPandoraStations(sourceAccount, searchTerm string) (*models.SearchStationResponse, error)

Search Pandora for artists and stations.

Parameters:

  • sourceAccount (string, required): Pandora account identifier
  • searchTerm (string, required): Artist or genre to search for

Returns:

  • *models.SearchStationResponse: Pandora search results with songs, artists, stations

Example:

results, err := client.SearchPandoraStations("user123", "Taylor Swift")

Validation:

  • sourceAccount cannot be empty

SearchSpotifyContent(sourceAccount, searchTerm string) (*models.SearchStationResponse, error)

Search Spotify for tracks, albums, and playlists.

Parameters:

  • sourceAccount (string, required): Spotify account identifier
  • searchTerm (string, required): Content to search for

Returns:

  • *models.SearchStationResponse: Spotify search results

Example:

results, err := client.SearchSpotifyContent("user@example.com", "Queen")

Validation:

  • sourceAccount cannot be empty

Station Management Methods

AddStation(source, sourceAccount, token, name string) error

Add a station to music service collection and immediately start playing it.

Parameters:

  • source (string, required): Music service identifier
  • sourceAccount (string, optional): Account identifier
  • token (string, required): Station token from search results
  • name (string, required): Display name for the station

Returns:

  • error: Error if operation fails

Example:

err := client.AddStation("PANDORA", "user123", "R4328162", "Classic Rock Radio")

Behavior:

  • Station is immediately selected and starts playing
  • Station is added to user’s collection permanently
  • Generates presetsUpdated WebSocket event if station is stored as preset

Validation:

  • source cannot be empty
  • token cannot be empty
  • name cannot be empty

RemoveStation(contentItem *models.ContentItem) error

Remove a station from music service collection.

Parameters:

  • contentItem (*models.ContentItem, required): Station content item with source and location

Returns:

  • error: Error if operation fails

Example:

err := client.RemoveStation(stationContentItem)

Behavior:

  • Station is removed from user’s collection
  • If station is currently playing, playback stops
  • Generates nowPlayingUpdated WebSocket event if playing station was removed

Validation:

  • contentItem cannot be nil
  • contentItem.Source cannot be empty
  • contentItem.Location cannot be empty

Models

NavigateRequest

Request structure for /navigate endpoint.

type NavigateRequest struct {
    Source        string        `xml:"source,attr"`
    SourceAccount string        `xml:"sourceAccount,attr,omitempty"`
    Menu          string        `xml:"menu,attr,omitempty"`
    Sort          string        `xml:"sort,attr,omitempty"`
    StartItem     int           `xml:"startItem"`
    NumItems      int           `xml:"numItems"`
    Item          *NavigateItem `xml:"item,omitempty"`
}

Constructors:

  • NewNavigateRequest(source, sourceAccount string, startItem, numItems int)
  • NewNavigateRequestWithMenu(source, sourceAccount, menu, sort string, startItem, numItems int)
  • NewNavigateRequestWithItem(source, sourceAccount string, startItem, numItems int, item *ContentItem)

NavigateResponse

Response structure from navigation operations.

type NavigateResponse struct {
    Source        string         `xml:"source,attr"`
    SourceAccount string         `xml:"sourceAccount,attr,omitempty"`
    TotalItems    int            `xml:"totalItems"`
    Items         []NavigateItem `xml:"items>item"`
}

Helper Methods:

  • GetPlayableItems() []NavigateItem - Filter items with Playable="1"
  • GetDirectories() []NavigateItem - Filter directory items (type="dir")
  • GetTracks() []NavigateItem - Filter track items (type="track")
  • GetStations() []NavigateItem - Filter station items (type="stationurl")
  • IsEmpty() bool - Check if response has no items

NavigateItem

Individual item within navigation response.

type NavigateItem struct {
    Playable           int                 `xml:"Playable,attr,omitempty"`
    Name               string              `xml:"name"`
    Type               string              `xml:"type"`
    ContentItem        *ContentItem        `xml:"ContentItem,omitempty"`
    MediaItemContainer *MediaItemContainer `xml:"mediaItemContainer,omitempty"`
    ArtistName         string              `xml:"artistName,omitempty"`
    AlbumName          string              `xml:"albumName,omitempty"`
}

Helper Methods:

  • GetDisplayName() string - Get formatted display name
  • IsPlayable() bool - Check if Playable="1"
  • IsDirectory() bool - Check if type="dir"
  • IsTrack() bool - Check if type="track"
  • IsStation() bool - Check if type="stationurl"
  • GetContentItem() *ContentItem - Get associated content item
  • GetArtwork() string - Get artwork URL from content item

Common Type Values:

  • "dir" - Directory/container
  • "track" - Music track
  • "stationurl" - Radio station
  • "playlist" - Playlist
  • "album" - Album

SearchStationRequest

Request structure for station search.

type SearchStationRequest struct {
    Source        string `xml:"source,attr"`
    SourceAccount string `xml:"sourceAccount,attr,omitempty"`
    SearchTerm    string `xml:",chardata"`
}

Constructor:

  • NewSearchStationRequest(source, sourceAccount, searchTerm string)

SearchStationResponse

Response structure from search operations.

type SearchStationResponse struct {
    DeviceID      string         `xml:"deviceID,attr"`
    Source        string         `xml:"source,attr"`
    SourceAccount string         `xml:"sourceAccount,attr,omitempty"`
    Songs         []SearchResult `xml:"songs>searchResult"`
    Artists       []SearchResult `xml:"artists>searchResult"`
    Stations      []SearchResult `xml:"stations>searchResult"`
}

Helper Methods:

  • GetSongs() []SearchResult - Get song results
  • GetArtists() []SearchResult - Get artist results
  • GetStations() []SearchResult - Get station results
  • GetAllResults() []SearchResult - Get all results combined
  • GetResultCount() int - Count total results
  • HasResults() bool - Check if any results found
  • IsEmpty() bool - Check if no results

SearchResult

Individual search result item.

type SearchResult struct {
    Source        string `xml:"source,attr"`
    SourceAccount string `xml:"sourceAccount,attr,omitempty"`
    Token         string `xml:"token,attr"`
    Name          string `xml:"name"`
    Artist        string `xml:"artist,omitempty"`
    Album         string `xml:"album,omitempty"`
    Logo          string `xml:"logo,omitempty"`
    Description   string `xml:"description,omitempty"`
}

Helper Methods:

  • IsSong() bool - Check if result is a song (has Artist field)
  • IsArtist() bool - Check if result is an artist (no Artist or Description)
  • IsStation() bool - Check if result is a station (has Description)
  • GetDisplayName() string - Get formatted name
  • GetFullTitle() string - Get name with artist for songs
  • GetArtworkURL() string - Get logo/artwork URL

Token Usage: The Token field is used with AddStation() to add the result to your collection.


AddStationRequest

Request structure for adding stations.

type AddStationRequest struct {
    Source        string `xml:"source,attr"`
    SourceAccount string `xml:"sourceAccount,attr,omitempty"`
    Token         string `xml:"token,attr"`
    Name          string `xml:"name"`
}

Constructor:

  • NewAddStationRequest(source, sourceAccount, token, name string)

StationResponse

Response structure from station management operations.

type StationResponse struct {
    Status string `xml:",chardata"`
}

Common Values:

  • "/addStation" - Station added successfully
  • "/removeStation" - Station removed successfully

HTTP Endpoints

POST /navigate

Browse content within a source.

Request Body:

<navigate source="TUNEIN" sourceAccount="">
  <startItem>1</startItem>
  <numItems>25</numItems>
</navigate>

Response Body:

<navigateResponse source="TUNEIN">
  <totalItems>5</totalItems>
  <items>
    <item Playable="1">
      <name>Station Name</name>
      <type>stationurl</type>
      <ContentItem source="TUNEIN" location="/v1/playback/station/s12345" isPresetable="true">
        <itemName>Station Name</itemName>
      </ContentItem>
    </item>
  </items>
</navigateResponse>

POST /searchStation

Search for stations and content.

Request Body:

<search source="PANDORA" sourceAccount="user123">Taylor Swift</search>

Response Body:

<results deviceID="AABBCCDDEEFF" source="PANDORA" sourceAccount="user123">
  <songs>
    <searchResult source="PANDORA" sourceAccount="user123" token="S123">
      <name>Love Story</name>
      <artist>Taylor Swift</artist>
      <logo>http://example.com/artwork.jpg</logo>
    </searchResult>
  </songs>
  <artists>
    <searchResult source="PANDORA" sourceAccount="user123" token="R456">
      <name>Taylor Swift</name>
      <logo>http://example.com/artist.jpg</logo>
    </searchResult>
  </artists>
</results>

POST /addStation

Add a station to collection and start playing.

Request Body:

<addStation source="PANDORA" sourceAccount="user123" token="R456">
  <name>Taylor Swift Radio</name>
</addStation>

Response Body:

<status>/addStation</status>

POST /removeStation

Remove a station from collection.

Request Body:

<ContentItem source="PANDORA" location="126740707481236361" sourceAccount="user123" isPresetable="true">
  <itemName>Taylor Swift Radio</itemName>
</ContentItem>

Response Body:

<status>/removeStation</status>

XML Schemas

Navigate Request Schema

<xs:element name="navigate">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="startItem" type="xs:int"/>
      <xs:element name="numItems" type="xs:int"/>
      <xs:element name="item" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="type" type="xs:string"/>
            <xs:element name="ContentItem" type="ContentItemType"/>
          </xs:sequence>
          <xs:attribute name="Playable" type="xs:int"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
    <xs:attribute name="source" type="xs:string" use="required"/>
    <xs:attribute name="sourceAccount" type="xs:string"/>
    <xs:attribute name="menu" type="xs:string"/>
    <xs:attribute name="sort" type="xs:string"/>
  </xs:complexType>
</xs:element>

Search Request Schema

<xs:element name="search">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="source" type="xs:string" use="required"/>
        <xs:attribute name="sourceAccount" type="xs:string"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>

ContentItem Type Schema

<xs:complexType name="ContentItemType">
  <xs:sequence>
    <xs:element name="itemName" type="xs:string" minOccurs="0"/>
    <xs:element name="containerArt" type="xs:string" minOccurs="0"/>
  </xs:sequence>
  <xs:attribute name="source" type="xs:string" use="required"/>
  <xs:attribute name="type" type="xs:string"/>
  <xs:attribute name="location" type="xs:string"/>
  <xs:attribute name="sourceAccount" type="xs:string"/>
  <xs:attribute name="isPresetable" type="xs:boolean"/>
</xs:complexType>

Error Codes

HTTP Status Codes

StatusMeaningDescription
200OKRequest successful
400Bad RequestInvalid parameters or XML
404Not FoundEndpoint or content not found
500Internal Server ErrorDevice error

Common Error Responses

Invalid Source:

<error>
  <code>INVALID_SOURCE</code>
  <message>Source 'INVALID' is not available</message>
</error>

Authentication Required:

<error>
  <code>AUTH_REQUIRED</code>
  <message>Source account required for this service</message>
</error>

Service Unavailable:

<error>
  <code>SERVICE_UNAVAILABLE</code>
  <message>PANDORA service is not configured</message>
</error>

Client-Side Validation Errors

The Go client performs validation before sending requests:

Error MessageCauseSolution
"source cannot be empty"Empty source parameterProvide valid source
"search term cannot be empty"Empty search queryProvide search term
"startItem must be >= 1"Invalid start positionUse 1-based indexing
"numItems must be >= 1"Invalid page sizeUse positive number
"content item cannot be nil"Nil ContentItemProvide valid ContentItem
"container item cannot be nil"Nil container for NavigateContainerProvide valid container
"Pandora source account cannot be empty"Missing Pandora accountConfigure Pandora account
"token cannot be empty"Missing station tokenUse token from search results
"station name cannot be empty"Missing station nameProvide station name

WebSocket Events

Navigation and station operations generate WebSocket events:

presetsUpdated

Generated when stations are added/removed that affect presets.

<presetsUpdated deviceID="AABBCCDDEEFF">
  <presets>
    <!-- Updated preset list -->
  </presets>
</presetsUpdated>

nowPlayingUpdated

Generated when station operations affect current playback.

<nowPlayingUpdated deviceID="AABBCCDDEEFF">
  <nowPlaying source="PANDORA">
    <ContentItem source="PANDORA" location="R456" sourceAccount="user123" isPresetable="true">
      <itemName>Taylor Swift Radio</itemName>
    </ContentItem>
    <track>Love Story</track>
    <artist>Taylor Swift</artist>
    <playStatus>PLAY_STATE</playStatus>
  </nowPlaying>
</nowPlayingUpdated>

Best Practices

Parameter Validation

Always validate parameters before API calls:

func validateNavigateParams(source string, startItem, numItems int) error {
    if source == "" {
        return fmt.Errorf("source cannot be empty")
    }
    if startItem < 1 {
        return fmt.Errorf("startItem must be >= 1")
    }
    if numItems < 1 {
        return fmt.Errorf("numItems must be >= 1")
    }
    return nil
}

Error Handling

Handle both network and API errors:

response, err := client.Navigate("TUNEIN", "", 1, 25)
if err != nil {
    // Check if it's a known API error
    if strings.Contains(err.Error(), "not available") {
        log.Printf("TuneIn not configured on device")
        return
    }
    return fmt.Errorf("navigation failed: %w", err)
}

Pagination

Use appropriate page sizes for different contexts:

// Small pages for interactive browsing
response, err := client.Navigate("TUNEIN", "", 1, 25)

// Larger pages for bulk processing
response, err := client.Navigate("STORED_MUSIC", "device/0", 1, 100)

Resource Management

Cache frequently accessed data:

type CachedClient struct {
    client      *client.Client
    sources     *models.Sources
    sourcesTime time.Time
}

func (c *CachedClient) GetSources() (*models.Sources, error) {
    if c.sources == nil || time.Since(c.sourcesTime) > 5*time.Minute {
        var err error
        c.sources, err = c.client.GetSources()
        c.sourcesTime = time.Now()
        return c.sources, err
    }
    return c.sources, nil
}

For complete usage examples and workflows, see NAVIGATION-GUIDE.md.

Last updated on