Skip to content

ZeroConf API

Warning:Commercial Hardware tools and the eSDK are available only for approved partners

The Spotify Connect ZeroConf API is an HTTP interface used for announcing and securely logging in to a hardware device. It enables a Spotify client, such as an iOS or Android device, to perform a login to a hardware device without the user entering a password.

The server providing the ZeroConf API can either be running inside the eSDK itself, or be implemented by a Spotify hardware partner. If the builtin ZeroConf server is enabled (see SpConfig::zeroconf_serve) and working satisfactorily on the hardware device, no ZeroConf implementation is needed from the Spotify hardware partner. Otherwise, it must be implemented to support the Spotify Connect feature.

Implementing the ZeroConf API, when not using the internal builtin ZeroConf service, requires:

  • a HTTP server
  • a JSON encoding and decoding library
  • a mDNS discovery service compatible with Apple's Bonjour.

The partner must then implement the behavior described in this document and hook it up appropriately with the calls to the Spotify Embedded API and their own integration code.

If SSL is supported by the web server, the ZeroConf API should be accessible via HTTPS. When HTTPS is enabled, it is preferred that non-secure HTTP access is disabled.

This is the ZeroConf process:

  • The Spotify desktop/smartphone client and the hardware device connect to the same network.
  • The device's ZeroConf API service is discovered by the client using a service discovery protocol.
  • The client logs in to the device using the ZeroConf API via HTTP.
  • The device is now ready to be used with Spotify Connect!

Discovery Service

The hardware device must use mDNS/DNS-SD in a way compatible with Apple's Bonjour, to advertise its IP address, the port of its HTTP service, and the path to the ZeroConf API implementation on the web server.

The DNS-SD service type is _spotify-connect._tcp.

  • A SRV record should be specified with the IP address and port
  • A TXT record should be provided with CPath=<path to ZeroConf implementation>. If a ZeroConf implementation is reachable on http://host:port/zeroconf, the TXT record shall be CPath=/zeroconf.

ZeroConf API

See the appendix for error codes and corresponding error strings.

  • Requests are made over HTTP using the GET or POST method.
    • All requests are answered by a response.
    • Every valid request has the action variable.
    • The application/x-www-form-urlencoded encoding is used for POST requests.
  • Responses are JSON objects (with Content-Type: application/json).
  • HTTP status code should match corresponding status from HTTP Status section.
  • All strings must support UTF-8 character encoding. All strings returned by the Spotify Embedded SDK will be in UTF-8 encoding.
  • If requests are handled on their own thread, keep in mind that the Embedded SDK is not thread-safe. You need to ensure that no two threads invoke SDK APIs at the same time. See threading.
  • If ZeroConf is turned off on a device that is inactive (ie a slave in a multiroom configuration), mDNS should be turned off. It's not enough to just turn off the webserver endpoints - they will still be hit by clients, spending unnecessary effort.

Mandatory fields in all responses:

FieldRequiredTypeDescription
statusYesIntegerA code indicating the result of the operation
statusStringYesStringThe string describing the status code
spotifyErrorYesIntegerThe last error code returned by a Spotify API call or the SpCallbackError() callback

Success example:


_10
{
_10
"status": 101,
_10
"statusString": "OK",
_10
"spotifyError": 0, "other data depending on action"
_10
}

Failure example:


_10
{
_10
"status": 402,
_10
"statusString": "ERROR-SPOTIFY-ERROR",
_10
"spotifyError": -119
_10
}

Add User

The API does not use any passwords. Only the user name and credentials blob are needed when logging in to Spotify.

Login should be performed by calling SpConnectionLoginZeroConf() with the data in this message.

Before sending a response, the application must do the following:

  • If a user's credentials are already stored, the existing user must be logged out using SpConnectionLogout() and the stored data must be deleted from persistent storage (same as resetusers resetUsers request).
  • Verify that SpConnectionLoginZeroConf() returns #kSpErrorOk (and fail the request if it returns something else).
  • Verify that login is successful by waiting for the #kSpConnectionNotifyLoggedIn event (and fail the request if SpCallbackError() is invoked).

The encrypted blob received in this ZeroConf message must not be saved. On a successful login, the SpCallbackConnectionNewCredentials() callback will be invoked with the credentials to save to persistent storage.

The user's credentials must not be saved to persistent storage unless the login is successful.

The status must not be returned until a #kSpConnectionNotifyLoggedIn or SpCallbackError() event is received.

If any required field is not specified, the response must be an error of type InvalidArguments, and the login function must not be called.

HTTP method: POST.

Extra parameters:

FieldRequiredTypeDescription
userNameYesStringUser name to login
blobYesStringEncrypted credentials blob for the user
clientKeyYesStringDecryption key provided by client
loginIdNoStringLogin ID for this addUser request
versionNoStringSpotify client ZeroConf API version number, ie "2.9.0". Can be used to handle compatibility issues
tokenTypeYesStringToken type provided by the client

Return: only status.

Get Information

HTTP method: GET.

Extra parameters:

FieldRequiredTypeDescription
versionNoStringSpotify client ZeroConf API version number, ie "2.9.0". May be used to handle compatibility issues

Return:

FieldRequiredTypeDescription
versionYesStringZeroConf API version number: "2.9.0"
deviceIDYesStringThe SpZeroConfVars::device_id field returned by SpZeroConfGetVars(). deviceID has to be unique enough to be used for identification on a local network.
publicKeyYesStringThe SpZeroConfVars::public_key field returned by SpZeroConfGetVars()
remoteNameYesStringThe SpZeroConfVars::remote_name field returned by SpZeroConfGetVars()
deviceTypeNoStringThe SpZeroConfVars::device_type field returned by SpZeroConfGetVars()
brandDisplayNameYesStringUser-facing brand name of the device
modelDisplayNameNoStringUser-facing model name of the device
libraryVersionYesStringThe SpZeroConfVars::library_version field returned by SpZeroConfGetVars()
resolverVersionYesStringThe SpZeroConfVars::resolver_version field returned by SpZeroConfGetVars()
groupStatusYesStringThe SpZeroConfVars::group_status field returned by SpZeroConfGetVars()
tokenTypeYesStringThe SpZeroConfVars::token_type field returned by SpZeroConfGetVars()
clientIDYesStringThe SpZeroConfVars::client_id field returned by SpZeroConfGetVars()
productIDYesIntegerThe SpZeroConfVars::product_id field returned by SpZeroConfGetVars()
scopeYesIntegerThe SpZeroConfVars::scope field returned by SpZeroConfGetVars()
availabilityYesStringThe SpZeroConfVars::availability field returned by SpZeroConfGetVars()
aliasesNoArrayThe SpZeroConfVars::aliases field returned by SpZeroConfGetVars()
supported_drm_media_formatsNoArrayThe SpZeroConfVars::supported_drm_media_formats field returned by SpZeroConfGetVars()
supported_capabilitiesNoIntegerBitmasked integer representing list of device capabilities. The SpZeroConfVars::supported_capabilities field returned by SpZeroConfGetVars()

Note The application is responsible for properly escaping special characters in the strings returned by SpZeroConfGetVars before sending them as part of the JSON response. See the JSON standard for the requirements.

Note Other Spotify clients may present brandDisplayName and the optional modelDisplayName to the user in the Connect menu and in other places. These strings may contain UTF-8 characters. The limitations of SpConfig::brand_name and SpConfig::model_name do not apply. However, during the certification process, we will verify that the fields are set to reasonable values that do not confuse users and can be displayed correctly by other Spotify clients.

Example:

Request:


_10
GET http://192.168.10.1:8080/cpath?action=getInfo&version=2.9.0

Response from device without aliases. The field "remoteName" defines the name to be displayed for the device.


_26
{
_26
"status": 101,
_26
"statusString": "OK",
_26
"spotifyError": 0,
_26
"version": "2.9.0",
_26
"deviceID": "0007F537F5ED",
_26
"deviceType": "SPEAKER",
_26
"remoteName": "John's \"Super\" Speaker",
_26
"publicKey": "<some-string>",
_26
"brandDisplayName": "Foo Corp™",
_26
"modelDisplayName": "X-2000 Portátil",
_26
"libraryVersion": "master-v2.15.1-g7890abcd",
_26
"resolverVersion": "1",
_26
"groupStatus": "GROUP",
_26
"tokenType": "accesstoken",
_26
"clientID": "<some-other-string>",
_26
"productID": 0,
_26
"scope": "streaming",
_26
"availability": "",
_26
"supported_drm_media_formats": [
_26
{"drm": 0, "formats": 35},
_26
{"drm": 1, "formats": 35},
_26
{"drm": 3, "formats": 1168}
_26
],
_26
"supported_capabilities": 1
_26
}

Response from a device using device aliases. In this case, the field remoteName should be empty in the response as the displayed name for respective alias is defined in the aliases field.


_38
{
_38
"status": 101,
_38
"statusString": "OK",
_38
"spotifyError": 0,
_38
"version": "2.9.0",
_38
"deviceID": "0007F537F5ED",
_38
"deviceType": "SPEAKER",
_38
"remoteName": "",
_38
"publicKey": "<some-string>",
_38
"brandDisplayName": "Foo Corp™",
_38
"modelDisplayName": "X-2000 Portátil",
_38
"libraryVersion": "master-v2.15.1-g7890abcd",
_38
"resolverVersion": "1",
_38
"groupStatus": "NONE",
_38
"tokenType": "accesstoken",
_38
"clientID": "<some-other-string>",
_38
"productID": 0,
_38
"scope": "streaming",
_38
"availability": "",
_38
"aliases": [
_38
{
_38
"name": "alias-one",
_38
"id": "1",
_38
"isGroup": "true"
_38
},
_38
{
_38
"name": "alias-two",
_38
"id": "2",
_38
"isGroup": "false"
_38
}
_38
],
_38
"supported_drm_media_formats": [
_38
{"drm": 0, "formats": 35},
_38
{"drm": 1, "formats": 35},
_38
{"drm": 3, "formats": 1168}
_38
],
_38
"supported_capabilities": 1
_38
}

Reset Users

The currently logged in user (if any) should be logged out using SpConnectionLogout. All user credentials should be deleted from the device's local storage. Any other persistent data related to ZeroConf should be cleared to factory-reset defaults.

HTTP method: POST.

Extra parameters: none.

Return: only status.

Device Aliases

Using ZeroConf, it is possible to announce multiple "virtual devices" from a device. This allows the eSDK device to expose, for instance, multiroom zones as ZeroConf devices.

Note There is no built-in support for multiroom audio forwarding in the eSDK. This feature enables an integration to announce partner supplied multiroom audio routing configurations directly in the Spotify app.

Device aliases will show up as separate devices in the Spotify app. When a device is selected for playback, you will know which alias from the device_alias_index parameter in the SpCallbackSelectedDeviceAliasChanged callback.

Device Aliases using built-in ZeroConf

If the built-in ZeroConf server is used, there is already support for device aliases, up to a maximum of SP_MAX_DEVICE_ALIASES. Simply configure the alias names in SpConfig::device_aliases,

for example:


_14
SpError err;
_14
struct SpConfig config;
_14
_14
memset(&config, 0, sizeof(config));
_14
_14
...
_14
config.device_aliases[0].display_name = "My Speaker";
_14
config.device_aliases[1].display_name = "Kitchen + Dining";
_14
config.device_aliases[2].display_name = "Upper floor";
_14
_14
config.display_name = NULL; // No display name is used because aliases are defined
_14
...
_14
_14
err = SpInit(&config);

When using SpConfig::device_aliases, SpConfig::display_name is not used.

Appendix

HTTP Status codes

The following table shows the different responses returned by the HTTP server to a client's request:

Status nameStatusHTTP status codeStatus stringResponse toUsage
Ok101200OKAllSuccessful operation
Bad102400ERROR-BAD-REQUESTAllWeb server problem or critically malformed request
Unknown103500ERROR-UNKNOWNAllFallback when no other error applies
NotImplemented104501ERROR-NOT-IMPLEMENTEDAllServer does not implement this feature
LoginFailed202200ERROR-LOGIN-FAILEDaddUserSpotify returned error when trying to login
MissingAction301400ERROR-MISSING-ACTIONAllWeb request has no action parameter
InvalidAction302400ERROR-INVALID-ACTIONAllWeb request has unrecognized action parameter
InvalidArguments303400ERROR-INVALID-ARGUMENTSAllIncorrect or insufficient arguments supplied for requested action
SpotifyError402200ERROR-SPOTIFY-ERRORAllA Spotify API call returned an error not covered by other error messages

Note It is permissible to send HTTP status code 200 in all cases, as long as a valid JSON reply is returned that contains the status, statusString, and spotifyError strings.