Self-hosted servers
Customers can run GameVox on their own hardware, and your bot works there. The cloud API forwards Discord-shape REST and gateway events down the customer's control channel, the self-hosted box runs them against its local database, and the response comes back up the same pipe. Most endpoints are transparent. The unsupported ones are listed below.
How it works
When your bot calls GET /guilds/{id} or
POST /channels/{id}/messages, the cloud
bot-API checks the target server's tier. If it's self-hosted,
we serialize the request (method, path, query, body,
bot_user_id) and send it down the persistent
control-channel WebSocket the customer's box holds open to us.
The self-hosted process runs the equivalent handler against its
own SQLite databases and returns a response envelope, which we
write back to your bot verbatim.
The forwarding happens at the bot-API layer. Your library never
sees it. No different token, no different gateway URL, no
different SDK. Your bot connects to the same
gateway.gamevox.com and calls the same
bot-api.gamevox.com whether the guild is
cloud-hosted or self-hosted.
Latency
Round-trip is bounded by the customer's WAN link plus SQLite
query time, usually 30–300 ms on top of a cloud call.
A 12 s end-to-end deadline is enforced. If a self-hosted
box stops responding (offline, upgrading, network cut) your
bot gets 504 Gateway Timeout within one second of
the deadline.
What works
Everything below runs against the self-hosted box's local data, with the same response shape as cloud.
- Messages: list, get, send, edit, delete, bulk-delete.
- Reactions: add, remove-self, remove-user, remove-all, remove-all-for-emoji, list users.
- Pins: pin, unpin, list.
- Typing:
POST /channels/{id}/typing. - Channels: get, patch, delete, list, create, reorder.
- Server (guild): get, patch (name and description).
- Members: list, search,
@me, get, patch, patch nick, kick, add or remove role. - Bans: list, get, put, delete.
- Roles: list, get, create, patch, reorder, delete, plus role permissions.
- Emojis: list, get (server-owned).
- Soundboard: list, get (server-owned).
- Audit log:
GET /guilds/{id}/audit-logs, bot-relevant entries only. - Vanity URL: GET (always the empty shape).
- Voice state: GET (live from the SFU), PATCH (mute, move, disconnect).
- Webhooks: full CRUD and execute. Rows live in cloud storage; the resulting message is written into the self-hosted channel via the same forwarding path used for bot sends, so channel messages badge correctly.
What returns 501 (accepted, not implemented)
-
PATCH .../voice-states/*withdeaf. Server-deafen isn't a primitive on the self-hosted SFU today. Mute, move (viachannel_id), and disconnect (viachannel_id: null) all work. -
PUT .../channels/{id}/permissions/{oid}. Self-hosted uses group-level permissions instead of per-channel overwrites, so there's nothing to apply a Discord overwrite to.DELETEreturns204(deleting an overwrite that doesn't exist is a no-op). -
PATCH .../guilds/{id}/vanity-url. Self-hosted servers don't have vanity URLs.
What returns 404 (not routed on self-hosted)
These endpoints touch resources that only exist in cloud infrastructure. Retry against a cloud guild if your bot needs them.
- All
/interactions/*, follow-up, and original-response endpoints. - All application-command CRUD (
/applications/{id}/commandsand the guild variants). - DM channel creation (
POST /users/@me/channels). - Cross-server user lookup (
GET /users/{id},GET /users/by-name/{name}). GET /users/@me/guilds.
Gateway events
Self-hosted boxes publish a subset of the events cloud emits. Your bot receives them through the same gateway session. No different subscription model.
Emitted from self-hosted today:
MESSAGE_CREATE,MESSAGE_UPDATE,MESSAGE_DELETE,MESSAGE_DELETE_BULKMESSAGE_REACTION_ADD,MESSAGE_REACTION_REMOVECHANNEL_CREATE,CHANNEL_UPDATE,CHANNEL_DELETECHANNEL_PINS_UPDATEGUILD_UPDATE(name / description changes)GUILD_MEMBER_ADD,GUILD_MEMBER_REMOVE,GUILD_MEMBER_UPDATE(nick or role change)GUILD_BAN_ADD,GUILD_BAN_REMOVEGUILD_ROLE_CREATE,GUILD_ROLE_UPDATE,GUILD_ROLE_DELETE(fired when the box's permission model changes)TYPING_STARTVOICE_STATE_UPDATE(join, leave, self/server mute, deafen)
Not yet emitted from self-hosted:
PRESENCE_UPDATE. Requires a new presence broadcaster on SH.- DM message events. Self-hosted has no cross-server DMs.
INTERACTION_CREATE. Self-hosted invocations of your bot's commands aren't forwarded yet.
Known fidelity gaps
- Self-mute vs server-mute: the SH SFU tracks
a single mute bit per participant rather than splitting
self_mutefrommutelike Discord.VOICE_STATE_UPDATEmirrors the same value into both fields; a server-mute unset may look like the user also un-self-muted. Bots reading only one of the two fields are fine; state-machine bots that mix them may want to prefermutefor moderator toggles. - Voice move fires two events: Discord's PATCH
voice-states/{uid}with a newchannel_idemits a singleVOICE_STATE_UPDATE; on SH the move is implemented as leave + re-join, so you'll see the target'schannel_idflash tonulland then to the new channel. Treat consecutive updates for the same user within a few hundred milliseconds as a single move.
Detecting self-hosted
The guild object doesn't carry a "self-hosted"
flag today (we're staying byte-identical with Discord). If
your bot needs to branch, the reliable signal is a
501 or 404 from one of the endpoints
above, with a JSON error body like:
{ "code": 0, "message": "voice-state modify not supported on self-hosted yet" }
If enough bots need cheaper detection we'll add a
features entry (e.g. "SELF_HOSTED")
to the guild payload. File feedback on your application's
Support tab if that would help.
Errors
502 Bad Gateway. The self-hosted box returned a malformed response. Rare; usually a version skew during upgrade.503 Service Unavailable. The control channel isn't currently connected. Retry with backoff.504 Gateway Timeout. The box didn't reply within 12 s.