Developer Portal
Experimental The bot & app platform is in active development. Self-hosted server support shipped on 2026-08-13 with a smaller feature surface than cloud. See what's supported.
← Docs

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/* with deaf. Server-deafen isn't a primitive on the self-hosted SFU today. Mute, move (via channel_id), and disconnect (via channel_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. DELETE returns 204 (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}/commands and 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_BULK
  • MESSAGE_REACTION_ADD, MESSAGE_REACTION_REMOVE
  • CHANNEL_CREATE, CHANNEL_UPDATE, CHANNEL_DELETE
  • CHANNEL_PINS_UPDATE
  • GUILD_UPDATE (name / description changes)
  • GUILD_MEMBER_ADD, GUILD_MEMBER_REMOVE, GUILD_MEMBER_UPDATE (nick or role change)
  • GUILD_BAN_ADD, GUILD_BAN_REMOVE
  • GUILD_ROLE_CREATE, GUILD_ROLE_UPDATE, GUILD_ROLE_DELETE (fired when the box's permission model changes)
  • TYPING_START
  • VOICE_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_mute from mute like Discord. VOICE_STATE_UPDATE mirrors 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 prefer mute for moderator toggles.
  • Voice move fires two events: Discord's PATCH voice-states/{uid} with a new channel_id emits a single VOICE_STATE_UPDATE; on SH the move is implemented as leave + re-join, so you'll see the target's channel_id flash to null and 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.

← Back to docs