Premium System

Premium System

The premium system aggregates status from multiple sources into a single unified check. This page documents how premium works, how it is configured, and how it surfaces in the dashboard.

Premium Sources

Premium status is resolved from the following sources, checked in order:

PrioritySourceTypeDescription
1Bot OwnerAutomaticOWNER_ID in config - always premium
2AdminAutomaticADMIN array in config - always premium
3PatreonWebhookActive pledges above MinTierPrice
4Ko-fiWebhookActive subscriptions via Ko-fi webhook
5Premium RoleGuildMembers with the configured premium role in the designated guild

If any source returns true, the user is considered premium. The system does not require all sources - only one match is needed.

Unified Premium Check

The premium check is performed by resolveDashboardAccess.ts > buildDashboardUserPerm(). This function:

  1. Checks if the user is the bot owner or admin.
  2. Queries PatreonService for active pledges tied to the user's Discord ID.
  3. Queries KofiService for active subscriptions tied to the user's Discord ID.
  4. Checks if the user has the configured premium role in the designated guild.

The result is a permission object containing boolean flags for each feature.

Patreon Integration

Setup

  1. Create a Patreon account and set up a creator page.
  2. Create an API client at Patreon Developers (opens in a new tab).
  3. Get your Creator Access Token and Campaign ID.
  4. Set the webhook URL to your WebServer's public URL.
Patreon:
  Enable: true
  AccessToken: "your_creator_access_token"
  CampaignId: "your_campaign_id"
  MinTierPrice: 500  # $5.00 minimum tier

To find your Campaign ID, run:

node scripts/getCampignId.js

How It Works

  1. PatreonService polls the Patreon API for active pledges.
  2. Pledge data is cached in patreon_cache.json.
  3. When a user's premium status is checked, the service looks up their Discord ID in the pledge data.
  4. Users with pledges at or above MinTierPrice are considered premium.

Guild Redemption

Patreon premium users can claim premium for specific guilds. The redeemedGuilds array tracks which guilds have been claimed by each patron. The number of guilds a patron can claim depends on their tier.

Ko-fi Integration

Setup

  1. Go to your Ko-fi settings → Webhooks.
  2. Set the webhook URL to: https://your-webserver-domain/kofi
  3. Copy the Verification Token.
KoFi:
  Enable: true
  VerificationToken: "your_verification_token"

How It Works

  1. Ko-fi sends webhook events to your Express WebServer at /kofi.
  2. The verification_token in the request body is validated against config.
  3. KofiService processes subscription events:
    • Subscription Created - adds premium status
    • Subscription Renewed - extends premium status
    • Subscription Cancelled - marks for expiration

Supported Events

Event TypeAction
DonationLogged (does not grant premium by default)
SubscriptionGrants premium status
CommissionLogged
Shop OrderLogged

Premium Role

Users in a specific Discord guild who have a designated role are automatically considered premium.

PremiumRole:
  Enable: true
  GuildId: "your_support_server_id"
  RoleId: "your_premium_role_id"

This is checked in real-time - when a user loses the role, they lose premium status immediately.

Dashboard Access Control

The DASHBOARD_ACCESS config controls which dashboard features require premium, voting, or are open to everyone:

DASHBOARD_ACCESS:
  Filters: ["Voter"]
  TwentyFourSeven: ["Voter"]
  Autoplay: ["Voter"]
  LastFm: ["Voter"]
  Spotify: ["Voter"]
  SongRequest: ["Voter"]
  Language: ["Voter"]
  StatusVoiceChannel: ["Voter"]
  Prefix: ["Voter"]
  DjRole: ["Voter"]
  ControlButton: ["Voter"]
  Playlist: ["Voter"]
  AiChat: ["Member"]

Access Levels

LevelWho Can AccessBehavior
MemberEveryoneNo restriction, no overlay
VoterUsers who voted on Top.ggShows "Vote Required" overlay with vote link. Premium always bypasses
PremiumPremium users onlyShows "Premium Required" overlay. Owner/Admin always bypass
ManagerManage Server permissionRequires guild-level permission
AdminBot admins onlyOnly users in the ADMIN array
OwnerBot owner onlyOnly the OWNER_ID user

How the Frontend Uses It

config.yml → resolveDashboardAccess.ts → getUserPremium API → Frontend components
  1. Backend reads DASHBOARD_ACCESS and evaluates the user's permission level.
  2. The /v1/user/:userId/premium endpoint returns per-feature access (boolean) and requirements (string level) objects.
  3. The dashboard proxy forwards this to /api/user/premium.
  4. Frontend components check access.<feature> and render a blurred overlay if access is denied.

Frontend Overlay

When access is denied, the dashboard renders:

  • A blurred overlay over the feature section
  • A lock icon
  • A title indicating the requirement (e.g., "Vote Required")
  • An action button (vote link or premium info)

Premium Data Flow

  Backend                    Dashboard Proxy              Frontend
┌────────────────┐    ┌───────────────────────┐    ┌──────────────────────┐
│ Premium Sources │    │ DashboardPlugin.ts    │    │                      │
│ • Patreon       │    │                       │    │ /profile             │
│ • Ko-fi         │--->│ GET /api/user/premium │--->│   -> isPremium badge │
│ • PremiumRole   │    │ GET /api/player/:gid  │    │                      │
│ • Owner/Admin   │    │                       │    │ /dashboard/[guildId] │
└────────────────┘    └───────────────────────┘    │   -> sidebar status  │
                                                   │   -> feature overlays│
                                                   └──────────────────────┘

Profile Page

The /profile page shows a premium badge next to the username:

  • Premium active: ★ Premium (green badge)
  • Not premium: ☆ Not Premium (muted badge)

Player Sidebar

The guild dashboard sidebar shows:

  • Premium active: Premium: Activated (green)
  • Not premium: Premium: Not Activated (muted)

Guild-Level vs User-Level

ContextChecksAPI
/profile pageUser-level onlyGET /api/user/premium (no guildId)
/dashboard/:guildIdUser + Guild levelGET /api/user/premium?guildId=...
Playlist accessUser-level onlyGET /api/playlists/access