Entwicklerportal
Experimentell Die Bot- & App-Plattform wird aktiv weiterentwickelt. Die Unterstützung für selbst gehostete Server ist am 13.08.2026 erschienen und bietet weniger Funktionen als die Cloud. Sieh dir an, was unterstützt wird.
← Doku

Mit GameVox anmelden

Lass Personen sich mit ihrem GameVox-Konto bei deiner Website oder App anmelden. Das ist der übliche OAuth2-Ablauf mit Autorisierungscode, aufgebaut wie bei Discord, und er braucht keinen Bot: Deine App fragt nach Teilen des Kontos, die Person stimmt zu, und dein Server erhält ein Token.

Wofür es gedacht ist

  • Anmeldung und Kontoverknüpfung. Erfahre, wer die Person ist (eine dauerhafte GameVox-Nutzer-ID, Benutzername, Avatar) und, mit ihrer Erlaubnis, ihre bestätigte E-Mail-Adresse.
  • Serverauswahl und Dashboards. Mit guilds siehst du, in welchen Servern die Person ist und wo sie Einstellungen verwalten kann.
  • Nicht, um im Namen der Person zu handeln. Ein Nutzer-Token kann keine Nachrichten senden, keinem Sprachkanal beitreten und nichts auf GameVox ändern. Alles, was innerhalb von GameVox handelt, braucht einen Bot.

Bevor du anfängst

  1. Erstelle eine Anwendung auf developers.gamevox.com. Die Client-ID im Tab OAuth2 ist deine client_id.
  2. Trage im Tab OAuth2 jede Redirect-URI ein, die deine App verwendet (bis zu 10). Sie müssen https:// sein, oder http://localhost / http://127.0.0.1 für die Entwicklung, ohne #fragment. Die redirect_uri, die du sendest, muss exakt einer davon entsprechen, einschließlich Query-String.
  3. Kopiere das Client-Secret. Es wird einmal angezeigt, wenn die App erstellt oder das Secret zurückgesetzt wird. Bewahre es auf deinem Server auf: Jede Token-Anfrage braucht es.

Endpunkte

GET  https://gamevox.com/oauth2/authorize/
POST https://app-api.gamevox.com/api/oauth2/token
POST https://app-api.gamevox.com/api/oauth2/token/revoke
GET  https://app-api.gamevox.com/api/users/@me
GET  https://app-api.gamevox.com/api/users/@me/guilds
GET  https://app-api.gamevox.com/api/oauth2/@me
PUT  https://api.gamevox.com/api/users/@me/applications/{application.id}/role-connection

Behalte den abschließenden Schrägstrich bei /oauth2/authorize/. Die Token- und Nutzer-Endpunkte antworten auch unter /api/v10/, sodass Bibliotheken, die eine Version in den Pfad setzen, unverändert funktionieren. Rollenverbindungen liegen auf api.gamevox.com, nicht auf app-api.

1. Schick die Person zu GameVox

Leite den Browser (per normaler Navigation, nicht in einem Popup oder Iframe) zur Autorisierungs-URL weiter:

https://gamevox.com/oauth2/authorize/
  ?response_type=code
  &client_id=123456789012345678
  &scope=identify%20email
  &redirect_uri=https%3A%2F%2Fyourapp.example.com%2Fauth%2Fgamevox
  &state=Zx81kq0vT2
ParameterErforderlichBeschreibung
response_type Ja Immer code.
client_id Ja Die Client-ID aus dem OAuth2-Tab deiner App.
scope Ja Durch Leerzeichen getrennt (URL-kodiert als %20 oder +). Siehe Scopes. Lass bot weg: Mit bot wird diese URL stattdessen zu einer Serverinstallation.
redirect_uri Ja Exakt eine deiner registrierten Redirect-URIs.
state Nein Ein nicht erratbarer Wert, der an die Sitzung der Person gebunden ist (bis zu 1024 Zeichen). Er kommt unverändert zurück; prüfe ihn, um Cross-Site-Request-Forgery zu verhindern.
code_challenge Nein Optionale PKCE-Challenge, 43 bis 128 Zeichen.
code_challenge_method Nein S256, wenn du eine Challenge sendest. plain wird abgelehnt.
prompt Nein none überspringt den Zustimmungsbildschirm, wenn die Person deine App bereits für alle diese Scopes freigegeben hat. Alles Neue wird weiterhin abgefragt.

Was die Person sieht

  • Einen Zustimmungsbildschirm auf gamevox.com mit Name, Symbol und Beschreibung deiner App, dem Konto, mit dem sie angemeldet ist, einer verständlichen Liste dessen, was du sehen kannst, und der Website, zu der sie weitergeleitet wird.
  • Ist sie abgemeldet, führt „Log in“ sie durch die GameVox-Web-App und direkt zurück zum selben Bildschirm.
  • Die Links zu deinen Nutzungsbedingungen und deiner Datenschutzerklärung erscheinen unter den Buttons, wenn du sie im Tab Allgemeine Informationen hinterlegst.

2. Verarbeite den Callback

Nachdem die Person auf „Authorize“ geklickt hat, schickt GameVox sie mit einem Code an deine Redirect-URI:

https://yourapp.example.com/auth/gamevox?code=3vR0b...&state=Zx81kq0vT2

Klickt sie stattdessen auf „Cancel“:

https://yourapp.example.com/auth/gamevox?error=access_denied
  &error_description=The+user+denied+the+request&state=Zx81kq0vT2
  • Lehne den Callback ab, wenn state nicht der Wert ist, den du für diesen Browser ausgegeben hast.
  • Ein Code läuft nach 10 Minuten ab und funktioniert nur einmal. Tausche ihn sofort ein, von deinem Server aus.

3. Tausche den Code gegen Tokens

Sende von deinem Server per POST einen formularkodierten Body (application/x-www-form-urlencoded, kein JSON) an den Token-Endpunkt:

curl -X POST https://app-api.gamevox.com/api/oauth2/token \
  -u "123456789012345678:CS.your-client-secret" \
  -d grant_type=authorization_code \
  -d code=3vR0b... \
  -d redirect_uri=https://yourapp.example.com/auth/gamevox
{
  "access_token": "GVO.mJ4c...",
  "token_type": "Bearer",
  "expires_in": 604800,
  "refresh_token": "GVR.9tQe...",
  "scope": "identify email"
}
  • Authentifiziere dich wie oben per HTTP Basic (client_id:client_secret) oder sende client_id und client_secret als Formularfelder.
  • redirect_uri muss derselbe Wert sein, den du in Schritt 1 gesendet hast. Füge code_verifier hinzu, wenn du PKCE verwendet hast.
  • Antworten enthalten Cache-Control: no-store. Lege das Client-Secret oder Tokens niemals in Browser-Code oder URLs ab.

4. Ruf die API auf

Sende das Access-Token als Authorization: Bearer. GET /users/@me braucht den Scope identify:

curl https://app-api.gamevox.com/api/users/@me \
  -H "Authorization: Bearer GVO.mJ4c..."
{
  "id": "1557709980780474368",
  "gamevox_id": "edf412bc-a7b8-4f2a-a810-8b9eb8c02462",
  "username": "alice",
  "discriminator": "0",
  "global_name": "alice",
  "avatar": null,
  "gamevox_avatar_url": "https://...",
  "email": "alice@example.com",
  "verified": true
}
  • id ist die dauerhafte GameVox-ID der Person. Verknüpfe deine Kontodatensätze damit; Benutzernamen können sich ändern. gamevox_id ist dieselbe Person in der nativen UUID-Form von GameVox.
  • email und verified sind nur mit dem Scope email vorhanden, und nur, wenn die Person eine E-Mail-Adresse hinterlegt hat. GameVox speichert nur bestätigte Adressen, daher ist verified immer true, wenn email gesetzt ist.
  • avatar ist immer null (Discord-Bibliotheken würden daraus einen Link auf das Discord-CDN bauen). Nutze gamevox_avatar_url; das Feld fehlt, wenn die Person kein Bild hat.

Die Server der Person

GET /users/@me/guilds braucht den Scope guilds:

[
  { "id": "1557445672742031360", "name": "Raid Night", "icon": null,
    "owner": true,  "permissions": "2251799813685247", "features": [] },
  { "id": "1557445672742031361", "name": "Guild Hall", "icon": null,
    "owner": false, "permissions": "1056", "features": [] }
]
  • permissions ist eine Zusammenfassung für die Serverauswahl, keine vollständige Berechnung: alle Bits (einschließlich ADMINISTRATOR) für Eigentümer und Admins, MANAGE_GUILD (32) plus VIEW_CHANNEL (1024), wo die Person Servereinstellungen bearbeiten kann, und VIEW_CHANNEL für alle anderen.
  • Bis zu limit Server pro Antwort (1 bis 200, Standard 200), die ältesten zuerst. Blättere weiter, indem du after oder before auf die id eines Servers aus der vorherigen Seite setzt, wie bei Discord.

Die aktuelle Autorisierung

GET /oauth2/@me funktioniert mit jedem Scope und sagt dir, zu welcher App das Token gehört, was gewährt wurde und wann es abläuft. user ist mit identify enthalten.

{
  "application": { "id": "123456789012345678", "name": "RaidPlanner", ... },
  "scopes": ["identify", "email"],
  "expires": "2026-10-15T15:03:20Z",
  "user": { "id": "1557709980780474368", "username": "alice", ... }
}

Verknüpfte Rollen

Mit role_connections.write kannst du festhalten, welches Konto die Person bei dir hat. Achte auf den Host: api.gamevox.com.

curl -X PUT \
  https://api.gamevox.com/api/users/@me/applications/123456789012345678/role-connection \
  -H "Authorization: Bearer GVO.mJ4c..." \
  -H "Content-Type: application/json" \
  -d '{"platform_name": "RaidPlanner", "platform_username": "ShadowMage", "metadata": {}}'

Die Person sieht das unter Settings > Authorized Apps als “Linked as ShadowMage on RaidPlanner”. Die Schlüssel in metadata müssen in den Rollenverbindungs-Metadaten deiner App definiert sein. Ein GET auf dieselbe URL liest den Eintrag zurück.

Erneuern

Access-Tokens gelten 7 Tage (expires_in ist in Sekunden). Hol dir mit dem Refresh-Token ein neues Paar:

curl -X POST https://app-api.gamevox.com/api/oauth2/token \
  -u "123456789012345678:CS.your-client-secret" \
  -d grant_type=refresh_token \
  -d refresh_token=GVR.9tQe...
  • Refresh-Tokens rotieren. Die Antwort enthält ein neues Refresh-Token, und das alte Refresh-Token und sein Access-Token funktionieren sofort nicht mehr. Speichere also das neue Paar, bevor du es verwendest.
  • Du kannst scope mitsenden, um das neue Token auf weniger Scopes einzuschränken. Die Anfrage nach einem Scope, den die Person nie gewährt hat, schlägt mit invalid_scope fehl.
  • Ein ungenutztes Refresh-Token läuft nach 90 Tagen ab. Pro Person und App gibt es höchstens 25 aktive Token-Paare; ein 26. verdrängt das älteste.

Widerrufen (Abmelden)

Widerrufe, wenn sich die Person von deiner App abmeldet. Jedes der beiden Tokens eines Paars widerruft das ganze Paar. Der Endpunkt antwortet bei einem gültigen Client immer mit 200, unabhängig davon, ob das Token existierte.

curl -X POST https://app-api.gamevox.com/api/oauth2/token/revoke \
  -u "123456789012345678:CS.your-client-secret" \
  -d token=GVO.mJ4c...

PKCE

Optional, und empfohlen, wenn die Autorisierungs-URL an einer Stelle gebaut wird, an der andere sie sehen könnten. GameVox unterstützt nur S256, und eine Token-Anfrage braucht trotzdem dein Client-Secret: Es gibt keine öffentlichen Clients ohne Secret.

// Before redirecting: keep the verifier with the user's pending login.
const verifier = base64url(crypto.randomBytes(32));
const challenge = base64url(crypto.createHash('sha256').update(verifier).digest());
// authorize URL: ...&code_challenge=CHALLENGE&code_challenge_method=S256
// token request: ...&code_verifier=VERIFIER (client secret still required)

Scopes

ScopeDeine App kann
identify ID, Benutzernamen und Avatar der Person lesen: GET /users/@me sowie user in GET /oauth2/@me.
email Die bestätigte E-Mail-Adresse der Person zu /users/@me hinzufügen.
guilds Die Serverliste der Person lesen: GET /users/@me/guilds.
role_connections.write Die Angaben zu verknüpften Rollen der Person für deine App lesen und schreiben.

Jeder andere Scope, einschließlich connections, guilds.join und applications.commands ohne bot, wird auf dem Zustimmungsbildschirm mit einem entsprechenden Hinweis abgelehnt.

Fehler

Die Token- und Widerrufs-Endpunkte liefern Fehler in der üblichen OAuth2-Form, {"error": "...", "error_description": "..."}, sodass OAuth-Bibliotheken sie direkt verarbeiten:

errorHTTPBedeutung
invalid_client 401 Falsche Client-ID oder falsches Secret, gelöschte App, oder das Konto, dem die App gehört, ist gesperrt.
invalid_grant 400 Der Code oder das Refresh-Token ist unbekannt, abgelaufen, bereits verwendet oder an eine andere App ausgegeben, oder redirect_uri bzw. code_verifier stimmen nicht überein. Kommt auch, nachdem die Person deine App deautorisiert hat.
invalid_request 400 Ein Pflichtfeld fehlt, oder der Body ist nicht formularkodiert.
invalid_scope 400 Eine Erneuerung hat einen Scope angefordert, den die ursprüngliche Freigabe nicht enthält.
unsupported_grant_type 400 Nur authorization_code und refresh_token werden unterstützt.
slow_down 429 Zu viele fehlgeschlagene Client-Authentifizierungen von deiner IP (30 pro Minute). Warte eine Minute.

API-Aufrufe mit einem ungültigen, abgelaufenen oder widerrufenen Token erhalten 401; ein Token ohne den nötigen Scope erhält 403 (50001 Missing Access). Antworten enthalten die üblichen X-RateLimit-*-Header, gezählt pro Person und App.

Wann der Zugriff endet

Ein Token kann schon vor seinem Ablauf ungültig werden. Das passiert, wenn:

  • die Person unter Settings > Authorized Apps auf Deauthorize klickt (alle Tokens, die du für sie hast, werden sofort ungültig, und dein Eintrag für verknüpfte Rollen zu ihr wird gelöscht)
  • das Konto der Person deaktiviert wird
  • deine Anwendung gelöscht wird
  • dein Entwicklerkonto gesperrt wird

Behandle ein 401 oder invalid_grant als “abgemeldet” und schick die Person erneut durch Schritt 1.

Vollständiges Beispiel (Node.js + Express)

Anmeldung mit State-Prüfung, Code-Austausch und Abruf der Personendaten. Node 18+ für das eingebaute fetch.

import express from 'express';
import crypto from 'node:crypto';

const CLIENT_ID = process.env.GAMEVOX_CLIENT_ID;
const CLIENT_SECRET = process.env.GAMEVOX_CLIENT_SECRET;
const REDIRECT_URI = 'https://yourapp.example.com/auth/gamevox';

// state must be tied to THIS browser, or someone can hand a victim a callback
// URL carrying the attacker's own code and sign them in as the attacker.
// A short-lived HttpOnly cookie does that without a session store.
const STATE_COOKIE = 'gv_oauth_state';
const readCookie = (req, name) =>
  (req.headers.cookie || '').split(';').map((c) => c.trim().split('='))
    .find(([k]) => k === name)?.[1] || '';

const app = express();

app.get('/login', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex');
  res.cookie(STATE_COOKIE, state, {
    httpOnly: true, secure: true, sameSite: 'lax', maxAge: 10 * 60 * 1000, path: '/auth/gamevox',
  });
  const url = new URL('https://gamevox.com/oauth2/authorize/');
  url.search = new URLSearchParams({
    response_type: 'code',
    client_id: CLIENT_ID,
    scope: 'identify email',
    redirect_uri: REDIRECT_URI,
    state,
  }).toString();
  res.redirect(url.toString());
});

app.get('/auth/gamevox', async (req, res) => {
  const { code, state, error } = req.query;
  const expected = readCookie(req, STATE_COOKIE);
  res.clearCookie(STATE_COOKIE, { path: '/auth/gamevox' });
  if (!expected || typeof state !== 'string' || state !== expected) {
    return res.status(400).send('Login expired or started in another browser');
  }
  if (error) return res.redirect('/?login=cancelled');
  if (typeof code !== 'string') return res.status(400).send('Missing code');

  const tokenRes = await fetch('https://app-api.gamevox.com/api/oauth2/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: 'Basic ' + Buffer.from(CLIENT_ID + ':' + CLIENT_SECRET).toString('base64'),
    },
    body: new URLSearchParams({ grant_type: 'authorization_code', code, redirect_uri: REDIRECT_URI }),
  });
  if (!tokenRes.ok) return res.status(502).send('GameVox login failed');
  const tokens = await tokenRes.json();

  const me = await fetch('https://app-api.gamevox.com/api/users/@me', {
    headers: { Authorization: 'Bearer ' + tokens.access_token },
  }).then((r) => r.json());

  // me.id is the stable GameVox user id: key your account record on it.
  // Store tokens.refresh_token server-side if you need access later.
  res.send('Signed in as ' + me.username);
});

app.listen(3000);

Unterschiede zu Discord

  • Nur der Authorization-Code-Grant. Kein Implicit Grant (response_type=token) und kein client_credentials.
  • Keine öffentlichen Clients: Jede Token-Anfrage braucht das Client-Secret, mit oder ohne PKCE.
  • Nutzerinstallationen (applications.commands ohne bot, integration_type=1) sind noch nicht verfügbar.
  • Keine Scopes connections, guilds.join, guilds.members.read oder rpc.
  • In /users/@me/guilds ist permissions eine Zusammenfassung für die Serverauswahl, keine vollständige Berechnung (siehe oben).

← Zurück zur Doku