How the HAP-Z1ES talks to the world over the LAN.
| Port | Proto | Service | Notes |
|---|---|---|---|
| 139 | TCP | NetBIOS Session | Samba 3.0.37 |
| 445 | TCP | SMB | Samba 3.0.37 — see 04-smb.md |
| 1900 | UDP | SSDP | UPnP discovery, server banner Linux/3.0 UPnP/1.0 Sony-HAP/1.0 |
| 60100 | TCP | HTTP (lighttpd) | UPnP device description + embedded web UI |
| 60200 | TCP | HTTP (lighttpd) | JSON-RPC ScalarWebAPI — the control plane |
Not open (verified empirically): 22 (SSH), 23 (telnet), 80 (HTTP), 443 (HTTPS), 5000, 8000, 8080, 8443, 10000 (Sony Home Audio API on cousin devices), 54480 (Sony Personal Audio API), 52323 (BRAVIA).
Implication: the alternate Sony ports referenced in python-songpal#29 are not used by the HAP — the HAP family is its own generation with its own port assignment. Don't waste time probing those.
A standard M-SEARCH * HTTP/1.1 to 239.255.255.250:1900 returns five replies, one for each advertised service:
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1800
LOCATION: http://192.168.1.28:60100/hap.xml
SERVER: Linux/3.0 UPnP/1.0 Sony-HAP/1.0
ST: upnp:rootdevice
USN: uuid:00000000-0000-1010-8000-<wifi-mac-no-colons>::upnp:rootdeviceAlso advertised:
urn:schemas-upnp-org:device:Basic:1urn:schemas-sony-com:service:ScalarWebAPI:1urn:schemas-sony-com:service:MusicConnect:1
The UUID format is 00000000-0000-1010-8000-<12 hex chars>. The last 12 hex chars are the Wi-Fi MAC (without colons), not the Ethernet MAC.
GET http://<ip>:60100/hap.xml returns the standard UPnP root device document, including the X_ScalarWebAPI extension:
<av:X_ScalarWebAPI_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
<av:X_ScalarWebAPI_Version>1.0</av:X_ScalarWebAPI_Version>
<av:X_ScalarWebAPI_BaseURL>http://<ip>:60200/sony</av:X_ScalarWebAPI_BaseURL>
<av:X_ScalarWebAPI_ServiceList>
<av:X_ScalarWebAPI_ServiceType>guide</av:X_ScalarWebAPI_ServiceType>
<av:X_ScalarWebAPI_ServiceType>system</av:X_ScalarWebAPI_ServiceType>
<av:X_ScalarWebAPI_ServiceType>audio</av:X_ScalarWebAPI_ServiceType>
<av:X_ScalarWebAPI_ServiceType>avContent</av:X_ScalarWebAPI_ServiceType>
</av:X_ScalarWebAPI_ServiceList>
</av:X_ScalarWebAPI_DeviceInfo>
<av:X_HAP_DeviceInfo xmlns:av="urn:schemas-sony-com:av">
<av:X_HAP_Version>0019404R</av:X_HAP_Version>
<av:X_HAP_MACAddr>80:56:f2:85:0e:27</av:X_HAP_MACAddr>
</av:X_HAP_DeviceInfo>Other endpoints on port 60100:
/HAP.html→ 301 to/HAP_app.html— a 272 KB HTML/JS embedded admin UI (CSS comments in Japanese — internal Sony tooling, not designed for end users)./ScalarWebAPI_SCPD.xml— UPnP SCPD descriptor (essentially empty — the real API is the JSON-RPC below)./MusicConnect_SCPD.xml— declaresTransportState(STOPPED/PLAYING/PAUSED_PLAYBACK/NO_MEDIA_PRESENT) andLastChangeevented variables./HAP-Z1ES_120.png,/HAP-Z1ES_48.png, etc. — device icons.
Firmware 19404R advertises a few endpoints that the daemon does not actually serve — leftovers from a shared Sony codebase. Confirmed dead on 19404R:
MusicConnect— declared in the UPnP description, butPOST /MusicConnect/controlreturns 404./sony/contentdb/v100/...(a REST-style content API the embeddedHAP_app.htmladmin UI calls —audio/{albums,artists,genres,tracks,playlists},contentplayer/v100/...). On 19404R a GET hangs and times out (0 bytes) and a POST returns 404, while the same:60200answers a normal ScalarWebAPIgetPowerStatus. SoHAP_app.htmlis a generic/older UI pointed at a backend this firmware lacks. The library is reachable via the JSON-RPCavContent.*methods (or read directly off disk —09-disk-layout.md), not this REST surface.
This is the real control plane. Every endpoint is POST http://<ip>:60200/sony/<service> with a JSON-RPC body:
{
"method": "<methodName>",
"id": 1,
"params": [...],
"version": "<version>"
}Services exposed:
/sony/system— power, system info, network settings/sony/audio— volume, sound settings (DSEE, DSD remastering, gapless, oversampling)/sony/avContent— playback control, library browse, now-playing info/sony/guide— API introspection (mostly disabled on HAP —getMethodTypesreturns{"results": []})
- Per-method versioning is non-uniform. Each method advertises its own version, and the server returns
error: [14, "Unsupported Version"]if you call the wrong one. There is no1.0for everything. Seeresearch/api-method-catalog.mdfor the working version of each known method. - HTTP
Expect: 100-continuetriggers417 Expectation Failed. Most Python and PowerShell clients send this header by default; you must disable it. In Python withrequests:session = requests.Session(); session.headers.update({'Expect': ''}). - Introspection is neutered.
getMethodTypesreturns{"results": []}at every version on every service, andgetSupportedApiInforeturns[12, "No Such Method"]. The full method dictionary has been recovered via APK decompile (seeresearch/notes/2026-05-25-apk-decompile-findings.mdandresearch/notes/2026-05-25-apk-deep-dive-downloadbydiff.md) plus live fuzzing. - Response bytes are UTF-8 JSON. Some libraries return them as
byte[]— decode with UTF-8 before parsing.
curl -X POST http://192.168.1.28:60200/sony/avContent \
-H 'Content-Type: application/json' \
--data '{"method":"getPlayingContentInfo","id":1,"params":[],"version":"1.2"}'Returns (formatted):
{
"id": 1,
"result": [{
"title": "Dan té dinyé la",
"artist": "Nahawa Doumbia",
"albumName": "La grande cantatrice Malienne vol. 3",
"fileName": "02 - Nahawa Doumbia - Dan té dinyé la.flac",
"uri": "audio:track?id=163756",
"albumID": "audio:album?id=11781",
"playlistUri": "audio:playinglist?id=69",
"storageUri": "storage:usb1",
"audioInfo": [{"codec":"flac","frequency":"44100","bandwidth":"16","bitrate":"1001000"}],
"audioCodec": ["flac"],
"audioFrequency": ["44100"],
"bandwidth": "16",
"bitrate": "1001000",
"durationMsec": 274000,
"positionMsec": 110000,
"state": "PLAYING",
"shuffleType": "off",
"repeatType": "off",
"playbackControlMode": "folder",
"playlistModifiedVersion": 7,
"favoriteType": "normal",
"listCount": 4,
"listIndex": 1,
"coverArtUrl": "http://192.168.1.28:60200/sony/avContent/storage/cover_art/A0002E05",
"backgroundColorR": 93,
"backgroundColorG": 160,
"backgroundColorB": 80,
"backgroundColorA": 255,
"composer": "Nahawa Doumbia"
}]
}Notice the typo playinglist (instead of playlist) — preserved here verbatim because that's the actual URI scheme. Future code that parses this must match the typo.
| Scheme | Example | Meaning |
|---|---|---|
audio:track?id=NNN |
audio:track?id=163756 |
A single track in the library DB |
audio:album?id=NNN |
audio:album?id=11781 |
An album in the library DB |
audio:artist?id=NNN |
(inferred) | An artist |
audio:playinglist?id=NNN |
audio:playinglist?id=69 |
A playlist (note typo) |
storage:usb1 |
storage:usb1 |
The USB-attached external drive |
storage:internal |
(inferred) | The internal HDD |
http://<ip>:60200/sony/avContent/storage/cover_art/<8-hex-id> returns the album art as JPEG (probably). The 8-hex ID is opaque — it does not match the album ID in audio:album?id=NNN directly.
The HAP exposes no push-notification mechanism. Confirmed via APK decompile (2026-05-25): Sony's own Android client uses four background polling threads at 5 s cadence rather than subscribing to events. There is no switchNotifications call anywhere in the client. No ws:// URLs. No WebSocket upgrade handshake. The phrase "WebSocket" appears in zero decompiled source files. Our earlier WebSocket upgrade probe on port 60200 returned 405 because the device doesn't speak WebSocket on that port at all.
Sony's polling endpoints (replicate this model in any third-party client):
| Thread | Endpoint | Method | Cadence |
|---|---|---|---|
| Volume + mute | POST /sony/audio |
getVolumeInformation v1.1 |
5 s |
| Now-playing | POST /sony/avContent |
getPlayingContentInfo v1.2 |
5 s |
| Power | POST /sony/system |
getPowerStatus v1.1 |
5 s |
| Library sync state | POST /sony/database |
checkSameDatabase v1.0 |
5 s |
Sony's "official example code" repo (sonydevworld/audio_control_api_examples) does demonstrate switchNotifications over WebSocket, but for cousin devices (BRAVIA TVs, STR-DN receivers, SRS speakers). The HAP family is a different generation and never picked up that capability.
See research/api-method-catalog.md for the living catalog with exact versions and parameter shapes.
- Sony BRAVIA Pro REST API spec — the most exhaustive Sony-published method/version dictionary.
rytilahti/python-songpal— Python implementation for STR-DN1080 and soundbars. Likely 80% portable to the HAP with port change + version remap.openHAB Sony binding PR #6884— built from Wireshark, covers TV/Bluray/AVR/soundbar. Java but readable as a method reference.