Developer Portal
Experimental The bot & app platform is in active development and currently works only on cloud-hosted GameVox servers. Self-hosted servers are not supported yet.
← Docs

Snowflakes

GameVox returns IDs in Discord's 64-bit snowflake format wherever the Discord API would. The bit layout, sort order, and timestamp-extraction math are identical — your existing snowflake-parsing code works without changes.

Format

Identical to Discord's: 42-bit timestamp + 5-bit worker + 5-bit process + 12-bit increment, big-endian inside a 64-bit unsigned integer.

┌─ 42 bits ─────────────────┬─ 5 ─┬─ 5 ─┬─ 12 ────────┐
│ ms since GameVox epoch    │ wkr │ prc │ increment   │
└───────────────────────────┴─────┴─────┴─────────────┘
 63                       22  21 17 16 12 11           0

Each segment matches Discord:

  • Timestamp (42 bits) — milliseconds since the GameVox epoch, see below.
  • Worker ID (5 bits) — assigned per running api task at startup via Redis atomic counter.
  • Process ID (5 bits) — paired with worker for a unique mint pool.
  • Increment (12 bits) — sequence per millisecond per (worker, process).

Epoch

GameVox uses the same epoch as Discord: 1420070400000 (2015-01-01 00:00:00 UTC). A snowflake parser written for Discord works on GameVox IDs unmodified — no constant to swap.

const SNOWFLAKE_EPOCH = 1420070400000n;

Wire format

Every snowflake on the REST / gateway wire is serialized as a JSON string, not a number. JavaScript loses precision above Number.MAX_SAFE_INTEGER (253-1) and a snowflake regularly exceeds that. Always parse via BigInt when you need to do math, and store as a string everywhere else.

// Correct
const id = BigInt(message.id);

// Wrong — silent precision loss
const id = Number(message.id);

Extracting the timestamp

JavaScript

function snowflakeToDate(snowflake) {
  const EPOCH = 1420070400000n;          // same as Discord
  const ms = Number((BigInt(snowflake) >> 22n) + EPOCH);
  return new Date(ms);
}

console.log(snowflakeToDate('182955831900192769'));
// → Date object — when this snowflake was minted

Python

from datetime import datetime, timezone

SNOWFLAKE_EPOCH = 1420070400000

def snowflake_to_dt(snowflake):
    ms = (int(snowflake) >> 22) + SNOWFLAKE_EPOCH
    return datetime.fromtimestamp(ms / 1000, tz=timezone.utc)

Java

long SNOWFLAKE_EPOCH = 1420070400000L;
long ms = (Long.parseUnsignedLong(snowflake) >>> 22) + SNOWFLAKE_EPOCH;
Instant when = Instant.ofEpochMilli(ms);

Sort order

Because the timestamp is in the high bits, a lexicographic string comparison of two snowflakes orders them chronologically — just like Discord. This is why before / after / around pagination on the messages endpoint works without an explicit timestamp field.

// In a message array, oldest → newest:
messages.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);

Native data and the alias table

Under the hood, GameVox-native objects (servers, channels, users, messages, etc.) use UUIDv4. The bot-compatibility layer mints a stable snowflake the first time an object is exposed to a bot and persists the pairing in the snowflake_aliases table. Every subsequent reference to that object — over REST or gateway — uses the same snowflake.

For messages we backfill snowflakes with the message's created_at as the source timestamp, so historical messages sort correctly when a bot first joins a channel. For everything else the alias is minted lazily at first exposure with NOW() as the timestamp, so the snowflake reflects when the bot saw the object, not necessarily when it was created.

Sharding hash

The standard Discord shard formula works as-is:

shardId = (BigInt(guildId) >> 22n) % BigInt(numShards);

Bots under 2,500 servers run on a single shard ([0, 1]) and never need to think about this. Larger bots get the same even-ish hash distribution Discord provides because the top 42 bits are time-monotonic, not random.

Gotchas

  • Don't compare snowflakes with == against a number literal. They're strings on the wire — compare to a string or convert both to BigInt.
  • The 42-bit timestamp wraps after roughly 139 years past the epoch. GameVox's snowflakes are good through 2165.
  • Don't infer creation time for a server / channel / role from its snowflake. Native objects predating the bot platform got their snowflake at first bot exposure, not at creation. Messages are the exception (backfilled with created_at).

← Back to docs