NodeLink
API Reference

WebSocket API

Real-time events and session management via WebSocket connection.

WebSocket API

NodeLink uses WebSocket connections to provide real-time communication between the server and clients. This connection is essential for receiving player events, track updates, and server statistics.

Connection

WebSocket Endpoint

WS
/v4/websocket
Connect to this endpoint to establish a WebSocket session.

Headers

AuthorizationstringRequired
The server password defined in config.js.
Client-NamestringRequired
Name and version of your client (e.g., "MyMusicBot/1.0.0").
User-IdstringRequired
Discord User ID of the bot. Must be 18-19 digits.
Session-Idstring
Session ID to resume. If provided, attempts to resume previous session.

Response

Resume a previous session after disconnection within the timeout period (default: 60 seconds).

Response

When successfully resumed using the Session-Id header, the server sends a ready event with resumed: true. All queued events from the disconnection period are immediately sent, followed by current state updates from all active players.

Incoming Events (Server → Client)

NodeLink sends various events to keep clients informed about playback status, player state, and server statistics. All events are sent as JSON messages.

Ready Event

Sent immediately after WebSocket connection is established.

Payload Structure

opstring
Always "ready"
resumedboolean
Whether this is a resumed session or new session
sessionIdstring
Unique session identifier for this connection

Example

{
  "op": "ready",
  "resumed": false,
  "sessionId": "xY7kP2mN8vQ4rL1s"
}

Player Update

Sent periodically (every 5 seconds) with current playback position and connection status for each active player.

Payload Structure

opstring
Always "playerUpdate"
guildIdstring
Discord guild ID where player is active
stateobject
Current player state
state.timenumber
Current Unix timestamp in milliseconds
state.positionnumber
Current track position in milliseconds
state.connectedboolean
Whether player is connected to voice channel
state.pingnumber
Voice connection ping in milliseconds

Example

{
  "op": "playerUpdate",
  "guildId": "987654321098765432",
  "state": {
    "time": 1701350400000,
    "position": 45230,
    "connected": true,
    "ping": 42
  }
}

Stats Event

Server statistics sent every minute with system resource usage and playback metrics.

Payload Structure

opstring
Always "stats"
playersnumber
Total number of active players across all guilds
playingPlayersnumber
Number of players currently playing audio
uptimenumber
Server uptime in milliseconds since start
memoryobject
Memory usage information in bytes
memory.freenumber
Free system memory
memory.usednumber
Memory used by NodeLink process
memory.allocatednumber
Total allocated memory
memory.reservablenumber
Maximum reservable memory
cpuobject
CPU usage information
cpu.coresnumber
Number of CPU cores
cpu.systemLoadnumber
System-wide CPU load (0.0-1.0)
cpu.processLoadnumber
NodeLink process CPU load (0.0-1.0)
frameStatsobject
Audio frame statistics (null if no active players)
frameStats.sentnumber
Total audio frames sent to Discord
frameStats.nullednumber
Frames that were null/empty
frameStats.deficitnumber
Frames that failed to send

Example

{
  "op": "stats",
  "players": 5,
  "playingPlayers": 3,
  "uptime": 3600000,
  "memory": {
    "free": 4294967296,
    "used": 536870912,
    "allocated": 1073741824,
    "reservable": 8589934592
  },
  "cpu": {
    "cores": 8,
    "systemLoad": 0.25,
    "processLoad": 0.08
  },
  "frameStats": {
    "sent": 15000,
    "nulled": 0,
    "deficit": 0
  }
}

Track Start Event

Sent when a track begins playing on any player.

Payload Structure

opstring
Always "event"
typestring
Always "TrackStartEvent"
guildIdstring
Discord guild ID where track started
trackobject
Full track information including encoded data
track.encodedstring
Base64 encoded track data
track.infoobject
Track metadata

Example

{
  "op": "event",
  "type": "TrackStartEvent",
  "guildId": "987654321098765432",
  "track": {
    "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAACyPgAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==",
    "info": {
      "identifier": "dQw4w9WgXcQ",
      "isSeekable": true,
      "author": "Rick Astley",
      "length": 212000,
      "isStream": false,
      "position": 0,
      "title": "Never Gonna Give You Up",
      "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
      "artworkUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg",
      "isrc": null,
      "sourceName": "youtube"
    }
  }
}

Track End Event

Sent when a track finishes playing or is stopped for any reason.

Payload Structure

opstring
Always "event"
typestring
Always "TrackEndEvent"
guildIdstring
Discord guild ID
trackobject
Track information
reasonstring
End reason: stopped, finished, loadFailed, replaced, cleanup

End Reasons

finishedstring
Track completed normally
stoppedstring
Track was manually stopped
replacedstring
Track was replaced by another track
loadFailedstring
Track failed to load
cleanupstring
Track ended due to cleanup (player destroyed)

Example

{
  "op": "event",
  "type": "TrackEndEvent",
  "guildId": "987654321098765432",
  "track": {
    "encoded": "QAAAjQIAJVJpY2sgQXN0bGV5IC0gTmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXAADlJpY2tBc3RsZXlWRVZPAAAAAAACyPgAC2RRdzR3OVdnWGNRAAEAK2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EAB3lvdXR1YmUAAAAAAAAAAA==",
    "info": {
      "identifier": "dQw4w9WgXcQ",
      "title": "Never Gonna Give You Up",
      "author": "Rick Astley",
      "length": 212000,
      "sourceName": "youtube"
    }
  },
  "reason": "finished"
}

Track Exception Event

Sent when an error occurs during track playback.

Payload Structure

opstring
Always "event"
typestring
Always "TrackExceptionEvent"
guildIdstring
Discord guild ID
trackobject
Track that caused the exception
exceptionobject
Error details
exception.messagestring
Human-readable error message
exception.severitystring
Error severity: common, suspicious, fault
exception.causestring
Root cause description

Severity Levels

commonstring
Expected error (e.g., track unavailable)
suspiciousstring
Unusual but recoverable error
faultstring
Critical error that prevents playback

Example

{
  "op": "event",
  "type": "TrackExceptionEvent",
  "guildId": "987654321098765432",
  "track": {
    "encoded": "...",
    "info": {
      "identifier": "invalid123",
      "title": "Invalid Track"
    }
  },
  "exception": {
    "message": "Failed to load track",
    "severity": "fault",
    "cause": "Video unavailable"
  }
}

Track Stuck Event

Sent when playback is stuck and hasn't progressed for the threshold period.

Payload Structure

opstring
Always "event"
typestring
Always "TrackStuckEvent"
guildIdstring
Discord guild ID
trackobject
Track that is stuck
thresholdMsnumber
Time in milliseconds before considering stuck (typically 10000ms)

Example

{
  "op": "event",
  "type": "TrackStuckEvent",
  "guildId": "987654321098765432",
  "track": {
    "encoded": "...",
    "info": {
      "identifier": "dQw4w9WgXcQ",
      "title": "Never Gonna Give You Up"
    }
  },
  "thresholdMs": 10000
}

WebSocket Closed Event

Sent when the voice WebSocket connection to Discord closes.

Payload Structure

opstring
Always "event"
typestring
Always "WebSocketClosedEvent"
guildIdstring
Discord guild ID
codenumber
Discord voice WebSocket close code
reasonstring
Human-readable close reason
byRemoteboolean
Whether the close was initiated by Discord (true) or locally (false)

Common Discord Voice Close Codes

4014number
Disconnected - channel was deleted or you were kicked
4006number
Session no longer valid
4015number
Voice server crashed

Example

{
  "op": "event",
  "type": "WebSocketClosedEvent",
  "guildId": "987654321098765432",
  "code": 4014,
  "reason": "Disconnected",
  "byRemote": true
}

Player Lifecycle Events

Emitted when a new player is created for a guild.

Payload Structure

opstring
Always "event"
typestring
Always "PlayerCreatedEvent"
guildIdstring
Discord guild ID

Example

{
  "op": "event",
  "type": "PlayerCreatedEvent",
  "guildId": "987654321098765432"
}
Emitted when a player is destroyed.

Payload Structure

opstring
Always "event"
typestring
Always "PlayerDestroyedEvent"
guildIdstring
Discord guild ID

Example

{
  "op": "event",
  "type": "PlayerDestroyedEvent",
  "guildId": "987654321098765432"
}
Emitted when player successfully connects to Discord voice channel.

Payload Structure

opstring
Always "event"
typestring
Always "PlayerConnectedEvent"
guildIdstring
Discord guild ID

Example

{
  "op": "event",
  "type": "PlayerConnectedEvent",
  "guildId": "987654321098765432"
}
Emitted when player is attempting to reconnect to voice.

Payload Structure

opstring
Always "event"
typestring
Always "PlayerReconnectingEvent"
guildIdstring
Discord guild ID

Example

{
  "op": "event",
  "type": "PlayerReconnectingEvent",
  "guildId": "987654321098765432"
}

Player State Events

Emitted when player volume is changed.

Payload Structure

opstring
Always "event"
typestring
Always "VolumeChangedEvent"
guildIdstring
Discord guild ID
volumenumber
New volume level (0-1000)

Example

{
  "op": "event",
  "type": "VolumeChangedEvent",
  "guildId": "987654321098765432",
  "volume": 80
}
Emitted when audio filters are modified.

Payload Structure

opstring
Always "event"
typestring
Always "FiltersChangedEvent"
guildIdstring
Discord guild ID
filtersobject
Active filter configuration

Example

{
  "op": "event",
  "type": "FiltersChangedEvent",
  "guildId": "987654321098765432",
  "filters": {
    "volume": 1.0,
    "equalizer": [
      { "band": 0, "gain": 0.2 }
    ]
  }
}
Emitted when seeking to a position in the track.

Payload Structure

opstring
Always "event"
typestring
Always "SeekEvent"
guildIdstring
Discord guild ID
positionnumber
New position in milliseconds

Example

{
  "op": "event",
  "type": "SeekEvent",
  "guildId": "987654321098765432",
  "position": 60000
}
Emitted when playback is paused or resumed.

Payload Structure

opstring
Always "event"
typestring
Always "PauseEvent"
guildIdstring
Discord guild ID
pausedboolean
Whether playback is now paused (true) or resumed (false)

Example

{
  "op": "event",
  "type": "PauseEvent",
  "guildId": "987654321098765432",
  "paused": true
}
Emitted when voice connection status changes.

Payload Structure

opstring
Always "event"
typestring
Always "ConnectionStatusEvent"
guildIdstring
Discord guild ID
connectedboolean
Current connection status

Example

{
  "op": "event",
  "type": "ConnectionStatusEvent",
  "guildId": "987654321098765432",
  "connected": true
}

On this page