Entrance sounds
An entrance sound is a short audio clip an account plays while it is connected to a voice channel. An account uploads a clip once into its own library, then assigns it to a scope: globally, in guild voice channels, in private calls, or in one named guild. Playback publishes no media. Voice defines voice state and placement.
Every route on this page is user-only, requires no permission, and acts on the caller’s own library.
Clip limits
Section titled “Clip limits”Every bound below is a fixed constant of the instance, and none is resolved from an account limit rule.
| Bound | Value |
|---|---|
| Clips per account | 8 |
| Decoded clip size1 | 1048576 bytes |
| Encoded upload payload1 | 1398134 characters |
| Clip duration2 | 100 through 5200 milliseconds |
| Display name | 1 through 32 characters after normalisation |
1 The character bound is the 1 MiB decoded ceiling expressed in base64 with 32 characters of slack, so it is the bound an oversized payload reaches first
2 Only Upload entrance sound applies the lower bound
The instance discovery document publishes a feature_voice_entrance_sounds limit key. That key gates the feature in the client. No route on this page consults it, so a library can be read, written, and played back regardless of its resolved value.
Supported containers
Section titled “Supported containers”The container is detected from the decoded bytes, so a filename, a data: media type, or any other declared type has no effect on the result. The detected container resolves to one of four stored extensions, and every other input fails with ENTRANCE_SOUND_INVALID_FORMAT.
| Detected container | Stored extension | Stored content type |
|---|---|---|
| MP3, MPEG1 | mp3 | audio/mpeg |
| Ogg2 | ogg | audio/ogg |
| MP4, QuickTime, AAC3 | m4a | audio/mp4 |
| WAV | wav | audio/wav |
1 An MPEG program stream resolves here as well as bare MPEG audio
2 An audio Ogg and a video Ogg both resolve here
3 The container alone decides this row, so an MP4 or QuickTime file with a video stream is accepted as long as a duration can be measured from it. A bare AAC stream outside an MP4 container is not detected and is rejected
FLAC, WebM, Matroska, AIFF, 3GPP, AVI, FLV, WMV, MPEG-TS, and every image type resolve to no extension and are rejected.
Entrance sound object
Section titled “Entrance sound object”One stored audio clip owned by one account. Every field except name is fixed at upload, and id is the only handle the other routes accept.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the sound |
| name | string | The display label shown for the clip (1-32 characters) |
| hash1 | string | The content digest of the stored audio, 16 hexadecimal characters |
| extension | string | The stored extension, one of mp3, ogg, m4a, and wav, chosen by the detected container |
| content_type | string | The MIME type the clip is stored and served with, derived from extension |
| duration_ms2 | integer | The measured duration in milliseconds (0-5200) |
| size_bytes | integer | The decoded size in bytes (0-1048576) |
| url3 | string | The absolute CDN URL the clip is fetched from |
| created_at | ISO8601 timestamp | The time the clip was uploaded |
1 The leading 16 hexadecimal characters of the MD5 digest of the decoded bytes, so two clips with identical audio have an identical hash
2 Measured from the decoded audio and rounded to the nearest millisecond
3 Built as /entrance-sounds/{user_id}/{hash}.{extension} on the instance’s media endpoint. The route that serves it accepts no credential, so anyone holding the URL can fetch the audio
Example
Section titled “Example”{ "id": "1501314428688998182", "name": "airhorn", "hash": "9f2c41ab77de0135", "extension": "mp3", "content_type": "audio/mpeg", "duration_ms": 1240, "size_bytes": 20416, "url": "https://cdn.example.com/entrance-sounds/1490000000000000000/9f2c41ab77de0135.mp3", "created_at": "2026-08-31T09:12:04.118Z"}Entrance sound selection object
Section titled “Entrance sound selection object”One scope and the clip assigned to it.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| scope_id | string | Entrance sound scope the selection applies to |
| sound_id | snowflake | The clip assigned to that scope |
A scope with no assigned sound has no selection object. Clearing a scope deletes its entry.
Example
Section titled “Example”{ "scope_id": "guild:1490000000000000123", "sound_id": "1501314428688998182"}Entrance sound scopes
Section titled “Entrance sound scopes”| Value | Description |
|---|---|
| global | Applies wherever no narrower scope is selected |
| guilds | Applies in guild voice channels |
| dms | Applies in direct message and group calls |
guild:{guild_id} | Applies in one named guild, where the ID is 1 through 20 digits |
scope_id must match one of the four forms exactly. Any other value fails with the validation code INVALID_FORMAT at the scope_id path.
List entrance sounds
Section titled “List entrance sounds”GET/v1/users/@me/entrance-soundsReturns the current account’s complete entrance sound library together with its per-scope selections.
Response body
Section titled “Response body”| Field | Type | Description |
|---|---|---|
| sounds | array[entrance sound object] | Every clip the account owns, at most 8 |
| selections | array[entrance sound selection object] | Every scope that currently has a sound assigned |
Both members are always present and both arrays are empty for an account that has uploaded nothing. A selection always names a sound present in sounds.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | response body | Library was returned |
Rate limit
Section titled “Rate limit”30 requests per minute for each authenticated user, on the user:entrance_sound:list bucket.
Upload entrance sound
Section titled “Upload entrance sound”POST/v1/users/@me/entrance-soundsDecodes, validates, and stores one audio clip in the current account’s library, and returns the created entrance sound object.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| name1 | string | The display label shown for the clip (1-32 characters) |
| audio2 | base64 string | The audio bytes of the clip, base64 encoded (1-1398134 characters) |
1 Trimmed before its length is measured
2 A data: URI prefix is accepted and discarded, and only the part after the first comma is measured and decoded
Invisible characters in name are not stripped and count toward the 32 character bound.
Validation
Section titled “Validation”Every failure below is a 400 INVALID_FORM_BODY. One response can report two of the first four rows when both fields are bad. The remaining rows are reported one at a time, in the order the table lists them.
| Failure | Validation code | Path |
|---|---|---|
| The field is absent or is a literal empty string1 | INVALID_FORMAT | name or audio |
| The normalised name is empty or longer than 32 characters | STRING_LENGTH_INVALID | name |
| The encoded payload is empty or longer than 1398134 characters2 | BASE64_LENGTH_INVALID | audio |
| The payload is not valid base64 | INVALID_BASE64_FORMAT | audio |
| The library already holds 8 clips | ENTRANCE_SOUND_QUOTA_REACHED | audio |
| The decoded bytes exceed 1048576 bytes | ENTRANCE_SOUND_SIZE_EXCEEDS_LIMIT | audio |
| The bytes resolve to no supported container, or their duration cannot be measured | ENTRANCE_SOUND_INVALID_FORMAT | audio |
| The measured duration is above 5200 ms or below 100 ms | ENTRANCE_SOUND_DURATION_EXCEEDS_LIMIT | audio |
| The validated clip could not be written to storage | FAILED_TO_UPLOAD_IMAGE | audio |
1 An empty string is read as null under input normalisation, and neither field accepts null
2 Measured after any data: prefix is discarded, so a value that is whitespace only, or that ends at its first comma, has zero payload characters and fails here
The first four rows are checked before the quota, so an account already holding 8 clips receives BASE64_LENGTH_INVALID or INVALID_BASE64_FORMAT for a malformed or over-long payload.
Both duration bounds report the same code at the audio path, and the entry has no member naming which of the two was crossed.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 201 | entrance sound object | Clip was stored |
| 400 | error response | Name or audio fails validation |
Side effects
Section titled “Side effects”The operation assigns no scope and emits no Gateway Dispatch.
Rate limit
Section titled “Rate limit”5 requests per 5 minutes for each authenticated user, on the user:entrance_sound:upload bucket.
Rename entrance sound
Section titled “Rename entrance sound”PATCH/v1/users/@me/entrance-sounds/{sound_id}Changes the display label of one clip and returns the updated entrance sound object.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| sound_id | snowflake | The ID of the sound |
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| name1 | string | Replacement display label (1-32 characters) |
1 Required, and normalised and bounded exactly as the name of Upload entrance sound
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | entrance sound object | Clip was renamed |
| 400 | error response | Name normalises to the empty string or exceeds 32 characters and the request returns STRING_LENGTH_INVALID at the name path, or the account owns no such clip and the request returns ENTRANCE_SOUND_NOT_FOUND at the sound_id path |
Side effects
Section titled “Side effects”Only the label changes. The stored audio is untouched, and every selection pointing at the clip keeps pointing at it. Fluxer emits no Gateway Dispatch.
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the user:entrance_sound:mutate bucket, which is shared with Delete entrance sound and Set entrance sound selection.
Delete entrance sound
Section titled “Delete entrance sound”DELETE/v1/users/@me/entrance-sounds/{sound_id}Deletes one clip from the current account’s library, clears every scope selection that pointed at it, and returns 204 with an empty body. An unknown clip, or a clip owned by another account, is a successful no-op.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| sound_id | snowflake | The ID of the sound |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 204 | empty | Clip was deleted, or no owned clip existed |
Side effects
Section titled “Side effects”Fluxer removes every selection naming the clip first, then the library entry, then the stored audio object unless another clip in the library has the same hash and extension. A storage failure is logged, and the request still returns 204, so the entry is removed either way. Fluxer emits no Gateway Dispatch.
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the shared user:entrance_sound:mutate bucket.
Set entrance sound selection
Section titled “Set entrance sound selection”PUT/v1/users/@me/entrance-sound-selectionsAssigns one of the account’s clips to one scope, or clears that scope, and returns 204 with an empty body. Each call addresses exactly one scope, and a scope that already has a sound is overwritten.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| scope_id | string | Entrance sound scope to write (1-32 characters) |
| sound_id1 | ?snowflake | The clip to assign, or null to clear the scope |
1 Required. An explicit null clears the scope, succeeds even when the scope had no selection, and looks up no clip
Fluxer accepts a guild:{guild_id} scope on its shape alone. It neither resolves the guild nor checks membership, so a selection can name a guild the account has left. A non-null sound_id must name a clip the account owns, and Fluxer writes the scope only after that lookup succeeds.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 204 | empty | Selection was written or cleared |
| 400 | error response | Scope is unrecognised and the request returns INVALID_FORMAT at the scope_id path, or the account owns no such clip and the request returns ENTRANCE_SOUND_NOT_FOUND at the sound_id path |
Side effects
Section titled “Side effects”Fluxer writes or removes the scope’s selection. One clip can be selected in any number of scopes at once. The operation emits no Gateway Dispatch, so the caller’s other sessions learn about the change only by listing the library again.
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the shared user:entrance_sound:mutate bucket.
Play entrance sound
Section titled “Play entrance sound”POST/v1/voice/channels/{channel_id}/entrance-soundFans the caller’s chosen clip out to everyone else connected to a voice channel and returns 204 with an empty body. The caller must already hold a voice state in that channel and must own the clip. Emits an ENTRANCE_SOUND_PLAY Gateway event.
Nothing is published to the media servers. Each recipient receives a Dispatch naming the clip’s CDN URL, then fetches and plays it locally.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | The ID of the voice channel the clip is played in |
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| sound_id | snowflake | The clip to play, drawn from the caller’s own library |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 204 | empty | Fan-out was attempted for every other connected account |
| 400 | error response | Caller holds no voice state in the channel, including when the channel does not exist, and the request returns ENTRANCE_SOUND_INVALID_SCOPE at the channel_id path, or the account owns no such clip and the request returns ENTRANCE_SOUND_NOT_FOUND at the sound_id path |
An ID naming no channel is refused exactly like a channel the caller is not connected to, so the response tells the two apart in neither direction. The connection check runs before the clip is looked up, so a caller who is not connected never learns whether the named clip exists.
Side effects
Section titled “Side effects”Fluxer sends one ENTRANCE_SOUND_PLAY Dispatch to every other account holding a voice state in the channel, at most once for each account, and never to the caller. A recipient whose Dispatch fails is skipped, and the request still returns 204.
Fluxer addresses the Dispatch to the account, so every session that account holds receives it, including sessions that are not in the channel. A client filters on channel_id.
Rate limit
Section titled “Rate limit”3 requests per 30 seconds for each authenticated user and channel ID, on the voice:entrance_sound:play::user_id::channel_id bucket.