Voice

Voice resources are used to interact with voice in Discord. For more information on connecting to voice, see the Voice Connections topic.

Voice State Object

Used to represent a user's voice connection status.

Voice State Structure
FieldTypeDescription
guild_id? 1?snowflakeThe guild ID this voice state is for
channel_id?snowflakeThe channel ID this user is connected to
user_idsnowflakeThe user ID this voice state is for
member? 1guild member objectThe guild member this voice state is for
session_idstringThe session ID this voice state is from
deafbooleanWhether this user is deafened by the guild, if any
mutebooleanWhether this user is muted by the guild, if any
self_deafbooleanWhether this user is locally deafened
self_mutebooleanWhether this user is locally muted
self_stream?booleanWhether this user is streaming using "Go Live"
self_videobooleanWhether this user's camera is enabled
suppressbooleanWhether this user's permission to speak is denied
request_to_speak_timestamp?ISO8601 timestampWhen which the user requested to speak

1 Omitted in the Gateway guild object.

Example Voice State
{
"channel_id": "157733188964188161",
"user_id": "80351110224678912",
"session_id": "90326bd25d71d39b9ef95b299e3872ff",
"deaf": false,
"mute": false,
"self_deaf": false,
"self_mute": true,
"suppress": false,
"request_to_speak_timestamp": "2021-03-31T18:45:31.297561+00:00"
}

Voice Region Object

Voice Region Structure
FieldTypeDescription
idstringThe unique ID for the region
namestringThe name of the region
optimalbooleanWhether this is the closest to the current user's client
deprecatedbooleanWhether this is a deprecated voice region (avoid switching to these)
custombooleanWhether this is a custom voice region (used for events, etc.)

Endpoints

Get Voice Regions

GET/voice/regions

Returns an array of voice region objects that can be used when setting a voice channel's rtc_region.

Get Guild Voice Regions

GET/guilds/{guild.id}/regions

Returns a list of voice region objects that can be used when setting a voice channel's rtc_region. Unlike the similar Get Voice Regions route, this returns VIP servers when the guild is VIP-enabled.

Upload Voice Public Key

PUT/voice/public-keys

Uploads a persistent public key used for voice encryption. Returns a 204 empty response on success.

More Information

How do I generate and use this key?

This key is used for persistent keypair signatures in the DAVE protocol. For further details, see the whitepaper.

Generating a keypair and signature can be done with the following Python pseudocode:

import base64
import requests
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
API_ENDPOINT = 'https://discord.com/api/v9'
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key().public_bytes(serialization.Encoding.X962, serialization.PublicFormat.CompressedPoint)
# https://datatracker.ietf.org/doc/html/rfc9000#name-variable-length-integer-enc
def encode_quic_varint(data):
length = len(data)
if length < 2**6:
return bytes([length]) + data
elif length < 2**14:
return bytes([(1 << 6) | (length >> 8), length & 0xFF]) + data
elif length < 2**30:
return bytes([(2 << 6) | (length >> 24), (length >> 16) & 0xFF, (length >> 8) & 0xFF, length & 0xFF]) + data
else:
return bytes([(3 << 6) | (length >> 56), (length >> 48) & 0xFF, (length >> 40) & 0xFF, (length >> 32) & 0xFF, (length >> 24) & 0xFF, (length >> 16) & 0xFF, (length >> 8) & 0xFF, length & 0xFF]) + data
# https://datatracker.ietf.org/doc/html/rfc9420/#name-signing
def sign_with_label(private_key, label, content) -> bytes:
label_bytes = b'MLS 1.0 ' + label.encode('ascii')
sign_content = encode_quic_varint(label_bytes) + encode_quic_varint(content)
signature = private_key.sign(sign_content, ec.ECDSA(hashes.SHA256()))
return signature
# The session ID is the static_client_session_id value from the READY payload
session_id = '00000000-0000-0000-0000-000000000000'.encode('ascii')
signature = sign_with_label(private_key, "DiscordSelfSignature", session_id + b':' + public_key)
data = {
'key_version': 1,
'public_key': 'data:application/octet-stream;base64,' + base64.b64encode(public_key).decode('utf-8'),
'signature': 'data:application/octet-stream;base64,' + base64.b64encode(signature).decode('utf-8'),
}
headers = {
'authorization': 'token',
# Rest of headers here
}
r = requests.put('%s/voice/public-keys' % API_ENDPOINT, json=data, headers=headers)
r.raise_for_status()
JSON Params
FieldTypeDescription
key_versionintegerThe version of the persistent key protocol (currently 1)
public_keycdn dataThe X9.62 P256 public key data
signaturecdn dataAn MLS style self-signature of the public key data with application label DiscordSelfSignature and content static_client_session_id:public_key

Verify Voice Public Key

POST/voice/{user.id}/match-public-key

Verifies a user's persistent public key for voice encryption against their uploaded ones.

More Information

Where do I get this key?

This key is used by another user to encrypt voice data. For further details, see the whitepaper.

JSON Params
FieldTypeDescription
key_versionintegerThe version of the persistent key protocol (currently 1)
public_keycdn dataThe X9.62 P256 public key data
Response Body
FieldTypeDescription
is_matchbooleanWhether the public key matches one of the user's uploaded persistent public keys

Get Voice Filters Catalog

GET/voice-filters/catalog

Returns the voice filters that can be used by the client.

Query String Params
FieldTypeDescription
vfm_versionintegerThe version of the voice filter native module
Response Body
FieldTypeDescription
models?map[str, voice filter model object]The ONNX machine learning models used by the voice filters
voices?arrayvoice filterThe voice filters available to the client
Voice Filter Model Structure
FieldTypeDescription
urlstringThe CDN URL to the ONNX model
Voice Filter Structure
FieldTypeDescription
idstringThe ID of the voice filter
models?array[string]The IDs of the ONNX models used by the voice filter
requires_premiumbooleanWhether the voice filter requires a premium (Nitro) subscription
availablebooleanWhether the voice filter is available to use
Example Response
{
"models": {
"vocoder_large_1": {
"url": "https://cdn.discordapp.com/assets/content/XXX.onnx"
},
"asr_large": {
"url": "https://cdn.discordapp.com/assets/content/XXX.onnx"
},
"pitch_small_3": {
"url": "https://cdn.discordapp.com/assets/content/XXX.onnx"
}
},
"voices": [
{
"id": "skye",
"models": ["vocoder_large_1", "asr_large", "pitch_small_3"],
"requires_premium": true,
"available": true
}
]
}

Get Current User Voice State

GET/guilds/{guild.id}/voice-states/@me

Returns the current user's voice state object in the guild.

Get User Voice State

GET/guilds/{guild.id}/voice-states/{user.id}

Returns the specified user's voice state object in the guild.

Modify Current User Voice State

PATCH/guilds/{guild.id}/voice-states/@me

Updates the current user's voice state in the given guild ID. Returns a 204 empty response on success. Fires a Voice State Update Gateway event.

Caveats

Modifying voice states is subject to some restrictions

There are currently several caveats for this endpoint:

  • channel_id must point to a stage channel
  • Current user must already have joined channel_id
  • You must have the MUTE_MEMBERS permission to unsuppress yourself; you can always suppress yourself
  • You must have the REQUEST_TO_SPEAK permission to request to speak; you can always clear your own request to speak
  • You can only set request_to_speak_timestamp to the present or a future time
JSON Params
FieldTypeDescription
channel_id?snowflakeThe ID of the channel the user is currently in
suppress?booleanWhether the user is suppressed in the channel
request_to_speak_timestamp??ISO8601 timestampWhen the user requested to speak

Modify User Voice State

PATCH/guilds/{guild.id}/voice-states/{user.id}

Updates another user's voice state in the given guild ID. Returns a 204 empty response on success. Fires a Voice State Update Gateway event.

Caveats

Modifying voice states is subject to some restrictions

There are currently several caveats for this endpoint:

  • channel_id must point to a stage channel
  • Target user must already have joined channel_id
  • You must have the MUTE_MEMBERS permission
  • When unsuppressed, user accounts will have their request_to_speak_timestamp set to the current time; bot users will not
  • When suppressed, the user will have their request_to_speak_timestamp removed
JSON Params
FieldTypeDescription
channel_idsnowflakeThe ID of the channel the user is currently in
suppress?booleanWhether the user is suppressed in the channel

Send Voice Channel Effect

POST/channels/{channel.id}/voice-channel-effects

Sends a voice channel effect to a voice channel. Returns a 204 empty response on success. Fires a Voice Channel Effect Send Gateway event.

JSON Params
FieldTypeDescription
animation_type??integerThe type of emoji animation, if applicable (default BASIC)
animation_id??integerThe ID of the emoji animation (0-20, default 0)
emoji_id??snowflakeThe ID of the custom emoji to send
emoji_name??stringThe emoji name or unicode character of the emoji to send
Voice Channel Effect Animation Type
ValueNameDescription
0PREMIUMA fun animation, requires a premium (Nitro) subscription
1BASICThe standard animation

Get Stream Preview

GET/streams/{stream_key}/preview

Returns a URL to a stream preview for the given stream key. Requires the CONNECT permission in the stream's channel.

Response Body
FieldTypeDescription
urlstringThe CDN URL to the stream preview

Upload Stream Preview

POST/streams/{stream_key}/preview

Uploads a stream preview for the given stream key. User must be the owner of the stream. Returns a 204 empty response on success.

JSON Params
FieldTypeDescription
thumbnailimage dataThe stream preview image

Broadcast Stream Notification

POST/streams/{stream_key}/notify

Broadcasts a stream notification to all friends of the current user that are in the same guild as the stream and have stream notifications enabled. User must be the owner of the stream and must be streaming in a guild. Returns a 204 empty response on success.