Last updated on August 9, 2024
Since the official Soulseek client and server is proprietary software, this documentation has been compiled thanks to years of reverse engineering efforts. To preserve the health of the Soulseek network, please do not modify or extend the protocol in ways that negatively impact the network.
If you find any inconsistencies, errors or omissions in the documentation, please report them.
Number |
---|
1 byte |
Number |
---|
2 bytes (little-endian) |
Number |
---|
4 bytes (little-endian) |
Number |
---|
8 bytes (little-endian) |
Number |
---|
1 byte (0 or 1) |
Length of String | String |
---|---|
uint32 | byte string |
Length of Bytes | Bytes |
---|---|
uint32 | byte array |
Type | Connection |
---|---|
P |
Peer To Peer |
F |
File Transfer |
D |
Distributed Network |
Reason | Description |
---|---|
INVALIDUSERNAME |
Username is longer than 30 characters or contains invalid characters (non-ASCII) |
INVALIDPASS |
Password for existing user is incorrect |
INVALIDVERSION |
Client version is outdated |
Code | Status |
---|---|
0 |
Offline |
1 |
Away |
2 |
Online |
Code | Status |
---|---|
0 |
No One |
1 |
Everyone |
2 |
Users in List |
3 |
Permitted Users |
Code | Direction |
---|---|
0 |
Download from Peer |
1 |
Upload to Peer |
String | Comments |
---|---|
Banned |
SoulseekQt uses ‘File not shared.’ instead |
Cancelled |
|
Complete |
|
File not shared. |
Note: Ends with a dot |
File read error. |
Note: Ends with a dot |
Pending shutdown. |
Note: Ends with a dot |
Queued |
|
Too many files |
|
Too many megabytes |
String | Comments |
---|---|
Blocked country |
Exclusive to Nicotine+, no longer used in Nicotine+ >=3.2.0 |
Disallowed extension |
Sent by Soulseek NS for filtered extensions |
File not shared |
Exclusive to Nicotine+, no longer used in Nicotine+ >=3.1.1 |
Remote file error |
Sent by Soulseek NS in response to legacy download requests |
User limit of x megabytes exceeded |
Exclusive to Nicotine+, no longer used in Nicotine+ >=3.1.1 |
User limit of x files exceeded |
Exclusive to Nicotine+, no longer used in Nicotine+ >=3.1.1 |
Code | Attribute (unit) |
---|---|
0 |
Bitrate (kbps) |
1 |
Duration (seconds) |
2 |
VBR (0 or 1) |
3 |
Encoder (unused) |
4 |
Sample Rate (Hz) |
5 |
Bit Depth (bits) |
These combinations are actively used by clients. Certain attributes can be missing if a file does not provide them.
{0: bitrate, 1: duration, 2: VBR}
{0: bitrate, 1: duration}
(MP3, OGG, WMA, M4A){1: duration, 4: sample rate, 5: bit depth}
(FLAC, WAV, APE){0: bitrate, 1: duration, 4: sample rate, 5: bit depth}
(WV){1: duration, 4: sample rate, 5: bit depth}
Server messages are used by clients to interface with the server over a connection (TCP). In Nicotine+, these messages are defined in slskmessages.py.
If you want a Soulseek server, check out Soulfind. Soulfind is obviously not exactly the same as the official proprietary Soulseek server, but it handles the protocol well enough (and can be modified).
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint32 | … |
We send this to the server right after the connection has been established. Server responds with the greeting message.
Data | Message Length | Message Code | Username Length | Username | Password Length | Password |
---|---|---|---|---|---|---|
Human | 72 | 1 | 8 | username | 8 | password |
Hex | 48 00 00 00 |
01 00 00 00 |
08 00 00 00 |
75 73 65 72 6e 61 6d 65 |
08 00 00 00 |
70 61 73 73 77 6f 72 64 |
Data | Version | Hash Length | Hash | Minor Version |
---|---|---|---|---|
Human | 160 | 32 | d51c9a7e9353746a6020f9602d452929 | 1 |
Hex | a0 00 00 00 |
20 00 00 00 |
64 35 31 63 39 61 37 65 39 33 35 33 37 34 36 61 36 30 32 30 66 39 36 30 32 64 34 35 32 39 32 39 |
01 00 00 00 |
48 00 00 00 01 00 00 00 08 00 00 00 75 73 65 72 6e 61 6d 65 08 00 00 00 70 61 73 73 77 6f 72 64 a0 00 00 00 20 00
00 00 64 35 31 63 39 61 37 65 39 33 35 33 37 34 36 61 36 30 32 30 66 39 36 30 32 64 34 35 32 39 32 39 01 00 00 00
160
for Nicotine+0x13000000
for 157 ns 13e, 0x11000000
for 157 ns 13cWe send this to the server to indicate the port number that we listen on (2234 by default).
If this value is set to zero, or the message is not sent upon login (which defaults the listen port to 0), remote clients handling a ConnectToPeer message will fail to properly purge the request. Confirmed in SoulseekQt 2020.3.12, but probably impacts most or all other versions.
1
We send this to the server to ask for a peer’s address (IP address and port), given the peer’s username.
1
Used to be kept updated about a user’s status. Whenever a user’s status changes, the server sends a GetUserStatus message.
Note that the server does not currently send stat updates (GetUserStats) when watching a user, only the initial stats in the WatchUser response. As a consequence, stats can be outdated.
Used when we no longer want to be kept updated about a user’s status.
The server tells us if a user has gone away or has returned.
OBSOLETE, no longer used
We send this to the server to tell a user we have ignored them.
The server tells us a user has ignored us.
OBSOLETE, no longer used
We send this to the server to tell a user we are no longer ignoring them.
The server tells us a user is no longer ignoring us.
Either we want to say something in the chatroom, or someone else did.
We send this message to the server when we want to join a room. If the room doesn’t exist, it is created.
Server responds with this message when we join a room. Contains users list with data on everyone.
As long as we’re in the room, the server will automatically send us status/stat updates for room users, including ourselves, in the form of GetUserStatus and GetUserStats messages.
Room names must meet certain requirements, otherwise the server will send a MessageUser message containing an error message. Requirements include:
We send this to the server when we want to leave a room.
The server tells us someone has just joined a room we’re in.
The server tells us someone has just left a room we’re in.
We send this to the server to attempt an indirect connection with a user. The server forwards the message to the user, who in turn attempts to establish a connection to our IP address and port from their end.
See also: Peer Connection Message Order
1
Chat phrase sent to someone or received by us in private.
We send this to the server to confirm that we received a private message. If we don’t send it, the server will keep sending the chat phrase to us.
OBSOLETE, use RoomSearch server message
We send this to the server when we search for something in a room.
We send this to the server when we search for something. Alternatively, the server sends this message outside the distributed network to tell us that someone is searching for something, currently used for UserSearch and RoomSearch requests.
The token is a number generated by the client and is used to track the search results.
We send our new status to the server. Status is a way to define whether we’re available (online) or busy (away).
When changing our own status, the server sends us a GetUserStatus message when enabling away status, but not when disabling it.
1 = Away
2 = Online
We send this to the server at most once per minute to ensure the connection stays alive.
The server used to send a response message in the past, but this is no longer the case.
Nicotine+ uses TCP keepalive instead of sending this message.
OBSOLETE
OBSOLETE, no longer used
OBSOLETE, use SendUploadSpeed server message
We used to send this after a finished download to let the server update the speed statistics for a user.
We send this to server to indicate the number of folder and files that we share.
The server sends this to indicate a change in a user’s statistics, if we’ve requested to watch the user in WatchUser previously. A user’s stats can also be requested by sending a GetUserStats message to the server, but WatchUser should be used instead.
OBSOLETE, no longer sent by the server
The server sends this to indicate if someone has download slots available or not.
The server sends this if someone else logged in under our nickname, and then disconnects us.
We send this to the server when we search a specific user’s shares. The token is a number generated by the client and is used to track the search results.
In the past, the server sent us this message for UserSearch requests from other users. Today, the server sends a FileSearch message instead.
OBSOLETE
OBSOLETE
We send this to the server when we are adding a recommendation to our “My recommendations” list, and want to receive a list of similar recommendations.
The server sends a list of similar recommendations to the one we want to add. Older versions of the official Soulseek client would display a dialog containing such recommendations, asking us if we want to add our original recommendation or one of the similar ones instead.
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we add an item to our likes list.
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we remove an item from our likes list.
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of personal recommendations and a number for each.
OBSOLETE
We send this to the server to ask for our own list of added likes/recommendations (called “My recommendations” in older versions of the official Soulseek client).
The server sends us the list of recommendations it knows we have added. For any recommendations present locally, but not on the server, the official Soulseek client would send a AddThingILike message for each missing item.
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of global recommendations and a number for each.
DEPRECATED, used in Soulseek NS but not SoulseekQt
We ask the server for a user’s liked and hated interests. The server responds with a list of interests.
OBSOLETE
We send this to the server to run an admin command (e.g. to ban or silence a user) if we have admin status on the server.
OBSOLETE, use PlaceInQueueResponse peer message
The server sends this to indicate change in place in queue while we’re waiting for files from another peer.
OBSOLETE, no longer sent by the server
The server tells us a new room has been added.
OBSOLETE, no longer sent by the server
The server tells us a room has been removed.
The server tells us a list of rooms and the number of users in them. When connecting to the server, the server only sends us rooms with at least 5 users. A few select rooms are also excluded, such as nicotine and The Lobby. Requesting the room list yields a response containing the missing rooms.
OBSOLETE, no results even with official client
We send this to search for an exact file name and folder, to find other sources.
A global message from the server admin has arrived.
OBSOLETE, no longer used
We send this to get a global list of all users online.
OBSOLETE, no longer used
Server message for tunneling a chat message.
The server sends us a list of privileged users, a.k.a. users who have donated.
We inform the server if we have a distributed parent or not. If not, the server eventually sends us a PossibleParents message with a list of possible parents to connect to. If no candidates are found, no such message is sent by the server, and we eventually become a branch root.
DEPRECATED, sent by Soulseek NS but not SoulseekQt
We send the IP address of our parent to the server.
The server informs us about the minimum upload speed required to become a parent in the distributed network.
The server sends us a speed ratio determining the number of children we can have in the distributed network. The maximum number of children is our upload speed divided by the speed ratio.
OBSOLETE, no longer sent by the server
OBSOLETE, no longer sent by the server
OBSOLETE, no longer sent by the server
OBSOLETE, no longer sent by the server
OBSOLETE, no longer sent by the server
The server sends us the username of a new privileged user, which we add to our list of global privileged users.
We ask the server how much time we have left of our privileges. The server responds with the remaining time, in seconds.
The server sends us an embedded distributed message. The only type of distributed message sent at present is DistribSearch (distributed code 3). If we receive such a message, we are a branch root in the distributed network, and we distribute the embedded message (not the unpacked distributed message) to our child peers.
We tell the server if we want to accept child nodes.
The server send us a list of max 10 possible distributed parents to connect to. Messages of this type are sent to us at regular intervals, until we tell the server we don’t need more possible parents with a HaveNoParent message.
The received list always contains users whose upload speed is higher than our own. If we have the highest upload speed on the server, we become a branch root, and start receiving SearchRequest messages directly from the server.
We send the server one of our wishlist search queries at each interval.
The server tells us the wishlist search interval.
This interval is almost always 12 minutes, or 2 minutes for privileged users.
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of similar users related to our interests.
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of recommendations related to a specific item, which is usually present in the like/dislike list or an existing recommendation list.
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends us a list of similar users related to a specific item, which is usually present in the like/dislike list or recommendation list.
The server returns a list of tickers in a chat room.
Tickers are customizable, user-specific messages that appear on chat room walls.
The server sends us a new ticker that was added to a chat room.
Tickers are customizable, user-specific messages that appear on chat room walls.
The server informs us that a ticker was removed from a chat room.
Tickers are customizable, user-specific messages that appear on chat room walls.
We send this to the server when we change our own ticker in a chat room. Sending an empty ticker string removes any existing ticker in the room.
Tickers are customizable, user-specific messages that appear on chat room walls.
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we add an item to our hate list.
DEPRECATED, used in Soulseek NS but not SoulseekQt
We send this to the server when we remove an item from our hate list.
We send this to the server to search files shared by users who have joined a specific chat room. The token is a number generated by the client and is used to track the search results.
In the past, the server sent us this message for RoomSearch requests from other users. Today, the server sends a FileSearch message instead.
OBSOLETE
We send this after a finished upload to let the server update the speed statistics for ourselves.
DEPRECATED, use WatchUser and GetUserStatus server messages
We ask the server whether a user is privileged or not.
We give (part of) our privileges, specified in days, to another user on the network.
DEPRECATED, sent by Soulseek NS but not SoulseekQt
DEPRECATED, no longer used
We tell the server what our position is in our branch (xth generation) on the distributed network.
We tell the server the username of the root of the branch we’re in on the distributed network.
DEPRECATED, sent by Soulseek NS but not SoulseekQt
We tell the server the maximum number of generation of children we have on the distributed network.
The server asks us to reset our distributed parent and children.
The server sends us a list of members (excluding the owner) in a private room we are in.
We send this to the server to add a member to a private room, if we are the owner or an operator.
The server tells us a member has been added to a private room we are in.
We send this to the server to remove a member from a private room, if we are the owner or an operator. Owners can remove operators and regular members, operators can only remove regular members.
The server tells us a member has been removed from a private room we are in.
We send this to the server to cancel our own membership of a private room.
We send this to the server to stop owning a private room.
OBSOLETE, no longer used
Unknown purpose
The server tells us we were added to a private room.
The server tells us we were removed from a private room.
We send this when we want to enable or disable invitations to private rooms.
We send this to the server to change our password. We receive a response if our password changes.
We send this to the server to add private room operator abilities to a member.
The server tells us a member received operator abilities in a private room we are in.
We send this to the server to remove private room operator abilities from a member.
The server tells us operator abilities were removed for a member in a private room we are in.
The server tells us we were given operator abilities in a private room we are in.
The server tells us our operator abilities were removed in a private room we are in.
The server sends us a list of operators in a private room we are in.
Sends a broadcast private message to the given list of online users.
DEPRECATED, used in Soulseek NS but not SoulseekQt
We ask the server to send us messages from all public rooms, also known as public room feed.
DEPRECATED, used in Soulseek NS but not SoulseekQt
We ask the server to stop sending us messages from all public rooms, also known as public room feed.
DEPRECATED, used in Soulseek NS but not SoulseekQt
The server sends this when a new message has been written in the public room feed (every single line written in every public room).
OBSOLETE, server sends empty list as of 2018
The server returns a list of related search terms for a search query.
The server sends a list of phrases not allowed on the search network. File paths containing such phrases should be excluded when responding to search requests.
We send this when we are not able to respond to an indirect connection request. We receive this if a peer was not able to respond to our indirect connection request. The token is taken from the ConnectToPeer message.
Do not rely on receiving this message from peers. Keep a local timeout for indirect connections as well.
See also: Peer Connection Message Order
Server tells us a new room cannot be created.
This message only seems to be sent if we try to create a room with the same name as an existing private room. In other cases, such as using a room name with leading or trailing spaces, only a private message containing an error message is sent.
Peer init messages are used to initiate a P
, F
or D
connection (TCP) to
a peer. In Nicotine+, these messages are defined in slskmessages.py.
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint8 | … |
Code | Message |
---|---|
0 |
Pierce Firewall |
1 |
Peer Init |
Used by SoulseekQt, Nicotine+ 3.2.1 and later, Soulseek.NET-based clients (slskd, Seeker)
Used by Soulseek NS, Nicotine+ 3.2.0 and earlier (excluding step 5-7), Museek+ (excluding step 7), soulseeX
This message is sent in response to an indirect connection request from another user. If the message goes through to the user, the connection is ready. The token is taken from the ConnectToPeer server message.
See also: Peer Connection Message Order
This message is sent to initiate a direct connection to another peer. The token is apparently always 0 and ignored.
See also: Peer Connection Message Order
0
0
Peer messages are sent to peers over a P
connection (TCP). Only a single
active connection to a peer is allowed. In Nicotine+, these messages are
defined in slskmessages.py.
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint32 | … |
Code | Message |
---|---|
1 |
Private Message OBSOLETE |
4 |
Shared File List Request |
5 |
Shared File List Response |
8 |
File Search Request OBSOLETE |
9 |
File Search Response |
10 |
Room Invitation OBSOLETE |
14 |
Cancelled Queued Transfer OBSOLETE |
15 |
User Info Request |
16 |
User Info Response |
33 |
Send Connect Token OBSOLETE |
34 |
Move Download To Top OBSOLETE |
36 |
Folder Contents Request |
37 |
Folder Contents Response |
40 |
Transfer Request |
41 |
Download Response DEPRECATED |
41 |
Upload Response |
42 |
Upload Placehold OBSOLETE |
43 |
Queue Upload |
44 |
Place In Queue Response |
46 |
Upload Failed |
47 |
Exact File Search Request OBSOLETE |
48 |
Queued Downloads OBSOLETE |
49 |
Indirect File Search Request OBSOLETE |
50 |
Upload Denied |
51 |
Place In Queue Request |
52 |
Upload Queue Notification DEPRECATED |
We send this to a peer to ask for a list of shared files.
A peer responds with a list of shared files after we’ve sent a SharedFileListRequest.
1
0
1
OBSOLETE, use UserSearch server message
We send this to the peer when we search for a file. Alternatively, the peer sends this to tell us it is searching for a file.
A peer sends this message when it has a file search match. The token is taken from original FileSearch, UserSearch or RoomSearch server message.
1
mp3
to show attributes0
1
mp3
to show attributes1
0
1
We ask the other peer to send us their user information, picture and all.
A peer responds with this after we’ve sent a UserInfoRequest.
We ask the peer to send us the contents of a single folder.
A peer responds with the contents of a particular folder (with all subfolders) after we’ve sent a FolderContentsRequest.
1
1
This message is sent by a peer once they are ready to start uploading a file to us. A TransferResponse message is expected from the recipient, either allowing or rejecting the upload attempt.
This message was formerly used to send a download request (direction 0) as well, but Nicotine+ >= 3.0.3, Museek+ and the official clients use the QueueUpload peer message for this purpose today.
DEPRECATED, use QueueUpload to request files
Response to TransferRequest
We (or the other peer) either agrees, or tells the reason for rejecting the file download.
Response to TransferRequest
We (or the other peer) either agrees, or tells the reason for rejecting the file upload.
OBSOLETE, no longer used
This message is used to tell a peer that an upload should be queued on their end. Once the recipient is ready to transfer the requested file, they will send a TransferRequest to us.
The peer replies with the upload queue placement of the requested file.
This message is sent whenever a file connection of an active upload closes. Soulseek NS clients can also send this message when a file cannot be read. The recipient either re-queues the upload (download on their end), or ignores the message if the transfer finished.
This message is sent to reject QueueUpload attempts and previously queued files. The reason for rejection will appear in the transfer list of the recipient.
This message is sent when asking for the upload queue placement of a file.
DEPRECATED, sent by Soulseek NS but not SoulseekQt
This message is sent to inform a peer about an upload attempt initiated by us.
File messages are sent to peers over a F
connection (TCP), and do not have
messages codes associated with them.
Message Contents |
---|
… |
Message |
---|
File Transfer Init |
File Offset |
We send this to a peer via a ‘F’ connection to tell them that we want to start uploading a file. The token is the same as the one previously included in the TransferRequest peer message.
Note that slskd and Nicotine+ <= 3.0.2 use legacy download requests, and send this message when initializing our file upload connection from their end.
We send this to the uploading peer at the beginning of a ‘F’ connection, to tell them how many bytes of the file we’ve previously downloaded. If nothing was downloaded, the offset is 0.
Note that Soulseek NS fails to read the size of an incomplete download if more than 2 GB of the file has been downloaded, and the download is resumed. In consequence, the client sends an invalid file offset of -1.
Distributed messages are sent to peers over a D
connection (TCP), and are
used for the distributed search network. Only a single active connection to a
peer is allowed. In Nicotine+, these messages are defined in slskmessages.py.
Message Length | Code | Message Contents |
---|---|---|
uint32 | uint8 | … |
Code | Message |
---|---|
0 |
Ping DEPRECATED |
3 |
Search Request |
4 |
Branch Level |
5 |
Branch Root |
7 |
Child Depth DEPRECATED |
93 |
Embedded Message |
DEPRECATED, sent by Soulseek NS but not SoulseekQt
We ping distributed children every 60 seconds.
Search request that arrives through the distributed network. We transmit the search request to our child peers.
We tell our distributed children what our position is in our branch (xth generation) on the distributed network.
If we receive a branch level of 0 from a parent, we should mark the parent as our branch root, since they won’t send a DistribBranchRoot message in this case.
We tell our distributed children the username of the root of the branch we’re in on the distributed network.
This message should not be sent when we’re the branch root.
DEPRECATED, sent by Soulseek NS but not SoulseekQt
We tell our distributed parent the maximum number of generation of children we have on the distributed network.
A branch root sends us an embedded distributed message. We unpack the distributed message and distribute it to our child peers.
The only type of distributed message sent at present is DistribSearch (distributed code 3).
This documentation exists thanks to efforts from the following projects: