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

Migrating from Discord

Run your existing Discord bot on GameVox by changing two configuration values: the REST base URL and the gateway URL. No code changes, no SDK swap.

1. Create a GameVox bot application

  1. Sign in at developers.gamevox.com
  2. Click New application
  3. Copy the bot token from the creation modal (shown once, save it now)

2. Point your library at GameVox

discord.js (Node, v14+)

const { Client, GatewayIntentBits } = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
  rest: { api: 'https://bot-api.gamevox.com/api' },
  ws:   { gatewayURL: 'wss://gateway.gamevox.com' },
});

client.login(process.env.GAMEVOX_BOT_TOKEN);

discord.py

import discord

discord.http.Route.BASE = 'https://bot-api.gamevox.com/api/v10'
discord.gateway.DiscordWebSocket.DEFAULT_GATEWAY = (
    'wss://gateway.gamevox.com/?v=10&encoding=json'
)

intents = discord.Intents.default()
intents.message_content = True

client = discord.Client(intents=intents)
client.run(GAMEVOX_BOT_TOKEN)

JDA (Java)

JDA jda = JDABuilder.createDefault(GAMEVOX_BOT_TOKEN)
    .setGatewayEncoding(GatewayEncoding.JSON)
    .setRestConfig(new RestConfig().setBaseUrl("https://bot-api.gamevox.com/api"))
    .setGatewayPool(scheduler)
    .build();
// JDA reads the gateway URL from /gateway/bot at startup,
// which our REST shim returns as wss://gateway.gamevox.com.

Eris (Node)

const Eris = require('eris');

const client = new Eris(GAMEVOX_BOT_TOKEN, {
  rest: { baseURL: 'https://bot-api.gamevox.com/api/v10' },
  ws: { gateway: 'wss://gateway.gamevox.com' },
  // Eris defaults to ETF encoding; force JSON (GameVox doesn't speak ETF yet).
});

client.connect();

DSharpPlus (.NET)

var discord = new DiscordClient(new DiscordConfiguration
{
    Token = Environment.GetEnvironmentVariable("GAMEVOX_BOT_TOKEN"),
    TokenType = TokenType.Bot,
    Intents = DiscordIntents.AllUnprivileged | DiscordIntents.MessageContents,
    ApiChannelEndpoint = "https://bot-api.gamevox.com/api/v10",
    GatewayUri = new Uri("wss://gateway.gamevox.com"),
});

await discord.ConnectAsync();

serenity (Rust)

let mut client = Client::builder(&token, intents)
    .event_handler(Handler)
    .api_base("https://bot-api.gamevox.com/api/v10")
    .gateway_url("wss://gateway.gamevox.com")
    .await?;
client.start().await?;

3. Install the bot on a server

From your application's OAuth2 tab in the developer portal, build an install URL with the permissions you need and share it. The URL takes the standard Discord shape:

https://gamevox.com/oauth2/authorize?client_id=YOUR_APP_ID&scope=bot+applications.commands&permissions=8

Server owners click the link, pick a GameVox server they own, and confirm.

4. What's different

The compatibility surface aims for 100%. Your bot's logic doesn't need to know it's not Discord. A few things to be aware of:

  • Apps are configured inside the client. GameVox can render your app's settings form in Server Settings, so a configurable bot no longer needs a hosted dashboard. This is the one deliberate incompatibility, and the only part of the platform with no Discord equivalent. Full docs →
  • Snowflake epoch: identical to Discord's (1420070400000, 2015-01-01 UTC). Parsers written for Discord work on GameVox IDs unchanged. More →
  • Threads / forum posts aren't supported yet.
  • Voice works with Lavalink. No special config. VOICE_SERVER_UPDATE just points at compatible-voice-gateway-{region}.gamevox.com and Lavalink handles the rest.
  • Custom emojis: server-owned emojis work in messages exactly as on Discord. App-owned emojis are managed in the developer portal for now; the bot-API only exposes GET. See Emojis.
  • Self-hosted servers: customers can run GameVox on their own hardware. Your bot works there too, with a smaller surface (no webhooks, no interactions yet). See Self-hosted docs.
  • EU / AP write latency: Bots hosted outside us-east will see ~80–150ms added latency on writes due to Aurora write forwarding. Host in us-east for best performance.

5. Configure your app from inside GameVox

On Discord, a bot with any configuration ships a web dashboard: a domain, an OAuth2 login, sessions, permission checks, hosting — usually so an operator can pick a log channel and toggle three features. GameVox already knows who the operator is, which server they are configuring, and whether they are allowed to, so it offers that surface to your app directly.

Your app describes a form over the gateway; GameVox renders it in Server Settings ▸ Integrations ▸ Settings and hands the edited values straight back. GameVox stores none of it — your app stays the only owner of its configuration.

The GameVox client's Server Settings window, showing an installed app's Settings tab with a language dropdown, a toggle and a channel checklist.
Rendered entirely from one bot's reply. The bot sent no channel ids — a picker names a kind and GameVox supplies this server's own choices. Server and channel names redacted.

The whole integration is one gateway handler and one REST call:

client.on("raw", async (packet) => {
  if (packet.t !== "APP_SETTINGS_REQUEST") return;
  const { nonce, server_id, action, values } = packet.d;

  const body = action === "save"
    ? { message: await save(server_id, values) }
    : { version: 2, sections: await describe(server_id) };

  await client.rest.post("/applications/@me/settings-response", {
    body: { nonce, ...body },
    query: new URLSearchParams({ server_id }),
  });
});

Twelve field types, including channel and role pickers GameVox populates for you, conditional fields, masked secrets and sections. In-App Settings →

6. Test it

The simplest smoke test: respond to !ping with pong.

client.on(Events.MessageCreate, async (msg) => {
  if (msg.author.bot) return;
  if (msg.content === '!ping') {
    await msg.reply('pong');
  }
});

If READY logs and the reply arrives, your bot is fully connected. Slash commands, voice, components: none require changes either.