aethex-forge/docs/discord-activity-reference.md
MrPiglr 25d584fd46
feat: Complete database migration and developer platform
- Applied all 31 pending Supabase migrations successfully
- Fixed 100+ policy/trigger/index duplication errors for shared database
- Resolved foundation_contributions schema mismatch (added user_id, contribution_type, resource_id, points columns)
- Added DROP IF EXISTS statements for all policies, triggers, and indexes
- Wrapped storage.objects operations in permission-safe DO blocks

Developer Platform (10 Phases Complete):
- API key management dashboard with RLS and SHA-256 hashing
- Complete API documentation (8 endpoint categories)
- 9 template starters + 9 marketplace products + 12 code examples
- Quick start guide and SDK distribution
- Testing framework and QA checklist

Database Schema Now Includes:
- Ethos: Artist/guild tracking, verification, tracks, storage
- GameForge: Games, assets, monetization
- Foundation: Courses, mentorship, resources, contributions
- Nexus: Creator marketplace, portfolios, contracts, escrow
- Corp Hub: Invoices, contracts, team management, projects
- Developer: API keys, usage logs, profiles

Platform Status: Production Ready 
2026-01-10 02:05:15 +00:00

16 KiB

Discord Activity Reference - Technical Documentation

Complete API reference and technical details for Discord Activity integration


Table of Contents

  1. Discord SDK API
  2. AeThex Discord Endpoints
  3. Authentication Methods
  4. Event Handling
  5. Discord Bot Commands
  6. Error Codes
  7. Rate Limits
  8. TypeScript Types

Discord SDK API

Initialization

import { DiscordSDK } from '@discord/embedded-app-sdk';

const discordSdk = new DiscordSDK(clientId: string, options?: {
  disableConsoleLogOverride?: boolean;
});

// Wait for SDK to be ready
await discordSdk.ready();

Authentication

authenticate()

Requests user authorization and returns an access token.

const auth = await discordSdk.commands.authenticate({
  scopes: string[];  // OAuth2 scopes to request
  access_token?: string;  // Optional: re-use existing token
});

// Returns
interface AuthResponse {
  access_token: string;
  token_type: 'Bearer';
  expires_in: number;  // Seconds until expiration
  scopes: string[];
  user: {
    id: string;
    username: string;
    discriminator: string;
    avatar: string | null;
    public_flags: number;
  };
}

Available Scopes:

  • identify - Read user profile (id, username, avatar)
  • email - Read user email address
  • guilds - See servers user is in
  • guilds.members.read - Read user's guild member data

authorize()

Similar to authenticate() but doesn't return user data.

const { code } = await discordSdk.commands.authorize({
  client_id: string;
  response_type: 'code';
  scope: string;  // Space-separated scopes
  state?: string;
});

User Methods

Get Current User

// Using Discord SDK
const user = await discordSdk.commands.getUser();

// Or via REST API
const response = await fetch('https://discord.com/api/v10/users/@me', {
  headers: {
    'Authorization': `Bearer ${access_token}`
  }
});
const user = await response.json();

User Object:

interface DiscordUser {
  id: string;  // Snowflake ID
  username: string;
  discriminator: string;  // "0" for new usernames
  global_name: string | null;  // Display name
  avatar: string | null;  // Avatar hash
  bot?: boolean;
  system?: boolean;
  mfa_enabled?: boolean;
  banner?: string | null;
  accent_color?: number | null;
  locale?: string;
  verified?: boolean;
  email?: string | null;  // Requires 'email' scope
  flags?: number;
  premium_type?: number;
  public_flags?: number;
}

Guild (Server) Methods

Get User Guilds

const response = await fetch('https://discord.com/api/v10/users/@me/guilds', {
  headers: {
    'Authorization': `Bearer ${access_token}`
  }
});
const guilds = await response.json();

Guild Object:

interface DiscordGuild {
  id: string;
  name: string;
  icon: string | null;
  owner: boolean;
  permissions: string;
  features: string[];
}

Activity Context

Get Instance Info

Information about the current Discord Activity session.

const instanceId = discordSdk.instanceId;  // Unique instance identifier
const channelId = discordSdk.channelId;    // Current channel ID
const guildId = discordSdk.guildId;        // Current guild ID

Get Participants

Get list of users currently in the Activity.

const participants = await discordSdk.commands.getInstanceConnectedParticipants();

interface Participant {
  id: string;
  username: string;
  discriminator: string;
  avatar: string | null;
  flags: number;
}

AeThex Discord Endpoints

These are the backend API endpoints provided by AeThex for Discord integration.

Authentication Endpoints

POST /api/discord/oauth/start

Initiates Discord OAuth flow.

Query Parameters:

  • action (optional): "login" or "link"
  • redirectTo (optional): URL to redirect after completion

Response:

{
  "redirect": "https://discord.com/api/oauth2/authorize?..."
}

GET /api/discord/oauth/callback

Handles OAuth callback from Discord.

Query Parameters:

  • code: Authorization code from Discord
  • state: State parameter (contains action and session info)

Behavior:

  • If action=login: Creates/logs in user, redirects to dashboard
  • If action=link: Links Discord to existing user, redirects to connections tab

Success Response:

  • Redirects to: /dashboard?tab=connections (link) or /dashboard (login)

Error Response:

  • Redirects to: /login?error=<code>&message=<details>

Account Linking Endpoints

POST /api/discord/create-linking-session

Creates a temporary session for Discord account linking.

Headers:

  • Authorization: Bearer <aethex_token>

Response:

{
  "sessionToken": "hex_string",
  "expiresAt": "2026-01-07T12:35:00Z"
}

Session Duration: 5 minutes

POST /api/discord/link

Links Discord account to authenticated user.

Headers:

  • Authorization: Bearer <aethex_token>

Body:

{
  "discordId": "123456789012345678",
  "username": "user#1234",
  "email": "user@example.com",
  "avatar": "avatar_hash"
}

Response:

{
  "success": true,
  "discordLink": {
    "discord_id": "123456789012345678",
    "user_id": "uuid",
    "linked_at": "2026-01-07T12:00:00Z"
  }
}

POST /api/discord/verify-code

Verifies a 6-digit linking code from Discord bot /verify command.

Body:

{
  "code": "123456",
  "discordId": "123456789012345678",
  "username": "user#1234"
}

Response:

{
  "success": true,
  "userId": "uuid",
  "message": "Account linked successfully"
}

Activity Endpoints

POST /api/discord/activity-auth

Exchanges Discord access token for AeThex session.

Body:

{
  "accessToken": "discord_access_token"
}

Response:

{
  "aethexToken": "jwt_token",
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "full_name": "Username"
  }
}

GET /api/discord/token

Retrieves stored Discord tokens for a user.

Headers:

  • Authorization: Bearer <aethex_token>

Response:

{
  "accessToken": "discord_access_token",
  "refreshToken": "discord_refresh_token",
  "expiresAt": "2026-01-07T13:00:00Z"
}

Admin Endpoints

POST /api/discord/admin-register-commands

Registers Discord bot slash commands.

Headers:

  • Authorization: Bearer <admin_token>

Response:

{
  "success": true,
  "commands": [
    { "name": "verify", "id": "cmd_id" }
  ]
}

Authentication Methods

Method 1: Discord Activity OAuth

For apps running inside Discord Activity.

import { DiscordSDK } from '@discord/embedded-app-sdk';

const discordSdk = new DiscordSDK(clientId);
await discordSdk.ready();

// Authenticate with Discord
const { access_token } = await discordSdk.commands.authenticate({
  scopes: ['identify', 'email', 'guilds']
});

// Exchange for AeThex token
const response = await fetch('/api/discord/activity-auth', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ accessToken: access_token })
});

const { aethexToken, user } = await response.json();

// Use AeThex token for subsequent requests
fetch('/api/games', {
  headers: { 'Authorization': `Bearer ${aethexToken}` }
});

Method 2: OAuth Redirect Flow

For standard web applications.

// Step 1: Redirect to OAuth start endpoint
window.location.href = '/api/discord/oauth/start?action=login';

// Step 2: User authorizes on Discord

// Step 3: Discord redirects to /api/discord/oauth/callback
// Step 4: Backend processes callback and redirects to dashboard
// Step 5: User is logged in with session cookies

Method 3: Account Linking

For linking Discord to existing AeThex account.

// In your frontend (user must be logged in)
async function linkDiscordAccount() {
  // Create linking session
  const response = await fetch('/api/discord/create-linking-session', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${aethexToken}`,
      'Content-Type': 'application/json'
    }
  });
  
  const { sessionToken } = await response.json();
  
  // Redirect to Discord OAuth with session token
  const state = btoa(JSON.stringify({
    action: 'link',
    sessionToken,
    redirectTo: '/dashboard?tab=connections'
  }));
  
  const oauthUrl = `https://discord.com/api/oauth2/authorize?` +
    `client_id=${discordClientId}&` +
    `redirect_uri=${encodeURIComponent(callbackUrl)}&` +
    `response_type=code&` +
    `scope=identify%20email%20guilds&` +
    `state=${state}`;
  
  window.location.href = oauthUrl;
}

Method 4: Bot Verify Command

For Discord bot users to link accounts.

// Discord bot generates code (server-side)
import { generateVerificationCode } from '@aethex/bot-utils';

const code = generateVerificationCode(discordUserId);
// Stores: { code: '123456', discord_id: '...', expires_at: ... }

// User visits verification page
// GET /discord-verify?code=123456

// Frontend auto-submits code
const response = await fetch('/api/discord/verify-code', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    code: '123456',
    discordId: discordUserId,
    username: 'user#1234'
  })
});

if (response.ok) {
  // Account linked! Redirect to dashboard
  window.location.href = '/dashboard?tab=connections';
}

Event Handling

Activity Events

discordSdk.subscribe('READY', () => {
  console.log('Activity is ready');
});

discordSdk.subscribe('VOICE_STATE_UPDATE', (voiceState) => {
  console.log('Voice state changed:', voiceState);
});

discordSdk.subscribe('SPEAKING_START', ({ userId }) => {
  console.log(`${userId} started speaking`);
});

discordSdk.subscribe('SPEAKING_STOP', ({ userId }) => {
  console.log(`${userId} stopped speaking`);
});

// Activity participants joined/left
discordSdk.subscribe('ACTIVITY_INSTANCE_PARTICIPANTS_UPDATE', (participants) => {
  console.log('Participants updated:', participants);
});

Discord Bot Commands

If you have a Discord bot, register these commands for better user experience.

/verify Command

Links Discord account to AeThex.

Registration:

{
  name: 'verify',
  description: 'Link your Discord account to AeThex',
  options: []
}

Handler (bot code):

async function handleVerifyCommand(interaction) {
  const discordUserId = interaction.user.id;
  const discordUsername = `${interaction.user.username}#${interaction.user.discriminator}`;
  
  // Generate 6-digit code
  const code = Math.floor(100000 + Math.random() * 900000).toString();
  
  // Store in database with 5min expiry
  await db.verification_codes.insert({
    code,
    discord_id: discordUserId,
    discord_username: discordUsername,
    expires_at: new Date(Date.now() + 5 * 60 * 1000)
  });
  
  // Send ephemeral message with link
  await interaction.reply({
    content: `🔗 Link your account:\n\n` +
             `Click: https://aethex.dev/discord-verify?code=${code}\n\n` +
             `Or enter code manually: **${code}**\n\n` +
             `⏱️ Code expires in 5 minutes.`,
    ephemeral: true
  });
}

Error Codes

OAuth Errors

Code Description Solution
invalid_request Missing required parameter Check OAuth URL parameters
unauthorized_client Client not authorized Verify client_id in Discord portal
access_denied User denied authorization User must authorize to continue
unsupported_response_type Invalid response_type Use response_type=code
invalid_scope Invalid or unsupported scope Check available scopes
redirect_uri_mismatch Redirect URI not registered Add URI to Discord OAuth2 settings

AeThex API Errors

Status Error Code Description
401 not_authenticated User not logged in or session expired
403 discord_already_linked Discord account linked to different user
404 user_not_found User doesn't exist
409 email_exists Email already registered (use link instead)
422 invalid_code Verification code invalid or expired
500 server_error Internal server error

Rate Limits

Discord API Rate Limits

  • Global: 50 requests per second
  • Per Route: Varies by endpoint (check headers)
  • OAuth Token: 1 request per 10 seconds per user

Response Headers:

X-RateLimit-Limit: 50
X-RateLimit-Remaining: 49
X-RateLimit-Reset: 1641040800
X-RateLimit-Reset-After: 2.5

AeThex API Rate Limits

  • Authentication endpoints: 10 requests per minute per IP
  • Account linking: 5 requests per minute per user
  • Activity auth: 30 requests per minute per user

Handling Rate Limits:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
    
    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After');
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      continue;
    }
    
    return response;
  }
  
  throw new Error('Max retries exceeded');
}

TypeScript Types

Discord Types

interface DiscordUser {
  id: string;
  username: string;
  discriminator: string;
  global_name: string | null;
  avatar: string | null;
  email?: string;
  verified?: boolean;
  mfa_enabled?: boolean;
  locale?: string;
  premium_type?: number;
  public_flags?: number;
}

interface DiscordGuild {
  id: string;
  name: string;
  icon: string | null;
  owner: boolean;
  permissions: string;
  features: string[];
}

interface OAuth2TokenResponse {
  access_token: string;
  token_type: 'Bearer';
  expires_in: number;
  refresh_token: string;
  scope: string;
}

AeThex Types

interface DiscordLinkResponse {
  success: boolean;
  discordLink: {
    discord_id: string;
    user_id: string;
    linked_at: string;
  };
}

interface ActivityAuthResponse {
  aethexToken: string;
  user: {
    id: string;
    email: string;
    full_name: string;
    avatar_url?: string;
  };
}

interface VerificationCodeResponse {
  success: boolean;
  userId: string;
  message: string;
}

interface LinkingSession {
  sessionToken: string;
  expiresAt: string;
}

Database Schema

Stores Discord account linkages.

CREATE TABLE discord_links (
  discord_id TEXT PRIMARY KEY,
  user_id UUID REFERENCES user_profiles(id) ON DELETE CASCADE,
  discord_username TEXT,
  discord_email TEXT,
  discord_avatar TEXT,
  access_token TEXT,
  refresh_token TEXT,
  token_expires_at TIMESTAMPTZ,
  linked_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_discord_links_user_id ON discord_links(user_id);

discord_linking_sessions Table

Temporary sessions for OAuth linking flow.

CREATE TABLE discord_linking_sessions (
  session_token TEXT PRIMARY KEY,
  user_id UUID REFERENCES user_profiles(id) ON DELETE CASCADE,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  expires_at TIMESTAMPTZ NOT NULL
);

CREATE INDEX idx_linking_sessions_expires ON discord_linking_sessions(expires_at);

verification_codes Table

6-digit codes for Discord bot /verify command.

CREATE TABLE verification_codes (
  code TEXT PRIMARY KEY,
  discord_id TEXT NOT NULL,
  discord_username TEXT NOT NULL,
  used BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  expires_at TIMESTAMPTZ NOT NULL
);

CREATE INDEX idx_verification_codes_discord_id ON verification_codes(discord_id);
CREATE INDEX idx_verification_codes_expires ON verification_codes(expires_at);


Last Updated: January 7, 2026
Discord API Version: v10
AeThex SDK Version: 2.0+