This feature requires:
- An active Elite Plan
- A valid API Key
See API Key - A whitelisted game where your admin is located
See Whitelist
π₯ Installation
1
Open Roblox Studio
Navigate to your Basic Admin Essentials model in Roblox Studio.
2
Inserting Script
Create a Module Script under the
Plugins folder, get rid of everything in it, and paste the following.Panora Demote Command
Panora Demote Command
PanoraDemote.lua
Copy
--[[
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π¦ Basic Admin Essentials Plugin β Demote Command
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Developed and maintained by: Panora Connect LLC
Website: https://panora.cc
This module integrates Panora Connectβs API with Basic Admin Essentials,
allowing workspace administrators to demote users directly in-game using
the official Panora ranking system.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βοΈ Configuration Guide
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The configuration is stored at the top of this script.
You can set the following variables:
β’ API_KEY β Your Panora API key (from your workspace)
β’ GROUP_ID β Your Roblox group ID
β’ COOLDOWN_TIME β Optional; adds cooldown between demotions
β’ WEBHOOK_URL β Optional; External webhook for demotion logs
β’ MIN_USERNAME_LENGTH β Optional; minimum username length to demote
β’ EveryoneAntiAbuse β Optional; prevents non-Everyone rank demotion
Once configured, simply place this plugin inside your Basic Admin
βPluginsβ folder. No other dependencies need to be modified.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π¬ Support & Contact
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
For assistance, please reach out through one of the following:
π§ Email: support@panora.cc
π Live Chat: https://app.panora.cc
π¬ Community Discord: https://discord.gg/panora
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
(c) 2025 Panora Connect LLC. All rights reserved.
Unauthorized redistribution or sale of this module is prohibited.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
]]
local HttpService = game:GetService("HttpService")
local GroupServiceModule = require(95677908346714)
local PanoraAPI = require(111358642560007)
local Plugin = function(...)
local Data = {...}
local remoteEvent = Data[1][1]
local remoteFunction = Data[1][2]
local returnPermissions = Data[1][3]
local Commands = Data[1][4]
local Prefix = Data[1][5]
local actionPrefix = Data[1][6]
local returnPlayers = Data[1][7]
local cleanData = Data[1][8]
local pluginName = script.Name
local pluginPrefix = Prefix
local pluginLevel = 2
local pluginUsage = "<username>"
local pluginDescription = "Demote a user | Panora"
local BASE_URL = "https://api.panora.cc/v1/ranker"
local API_KEY = "YOUR_PANORA_API_KEY"
local GROUP_ID = 000000
local COOLDOWN_TIME = 0
local WEBHOOK_URL = ""
local MIN_USERNAME_LENGTH = 2
local EveryoneAntiAbuse = true
--βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-- β οΈ DO NOT EDIT PAST THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING. WE DO NOT ASSIST WITH MODIFIED CODES!!
--βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
local recentDemotions = {}
local function log(tag, ...)
print(string.format("[%s]", tag), ...)
end
local function findPreviousRank(currentRank)
local roles = GroupServiceModule.getGroupRoles(GROUP_ID)
table.sort(roles, function(a, b)
return a.Rank < b.Rank
end)
for i = #roles, 1, -1 do
if roles[i].Rank < currentRank then
return roles[i]
end
end
return nil
end
local function processDemotion(player, target)
log("DEMOTE", "Processing", target.Name)
if player.UserId == target.UserId then
log("DEBUG", "Skipped self-demotion for", target.Name)
return string.format("%s - Skipped (Cannot demote self)", target.Name)
end
local last = recentDemotions[target.UserId]
if last and os.time() - last < COOLDOWN_TIME then
local remaining = COOLDOWN_TIME - (os.time() - last)
log("DEBUG", string.format("Cooldown active for %s (%ds left)", target.Name, remaining))
return string.format("%s - Cooldown active (%ds left)", target.Name, remaining)
end
local currentRank = GroupServiceModule.getUserGroupRank(target.UserId, GROUP_ID)
local currentRoleName
for _, role in pairs(GroupServiceModule.getGroupRoles(GROUP_ID)) do
if role.Rank == currentRank then
currentRoleName = role.Name
break
end
end
local prevRank = findPreviousRank(currentRank)
if not prevRank then
log("DEBUG", string.format("%s is already at lowest rank", target.Name))
return string.format("%s - Already at lowest rank", target.Name)
end
local rankData = {
rankerName = player.Name,
rankerId = player.UserId,
rankeeName = target.Name,
rankeeId = target.UserId,
newRankId = prevRank.Rank,
oldRankName = currentRoleName,
command = "demote | BAE Integration",
prefix = Prefix,
webhookUrl = WEBHOOK_URL
}
local success, message = PanoraAPI.rankUser(BASE_URL, API_KEY, rankData)
if success then
recentDemotions[target.UserId] = os.time()
log("PANORA", string.format("Demotion succeeded for %s (%s)", target.Name, message))
return string.format("%s - Success", target.Name)
else
log("PANORA", string.format("Demotion failed for %s (%s)", target.Name, message))
return string.format("%s - Failed (%s)", target.Name, message or "Unknown error")
end
end
local function processMultiple(player, targets)
local results = {}
for _, t in pairs(targets) do
local result = processDemotion(player, t)
table.insert(results, result)
end
local summary = table.concat(results, "\n")
remoteEvent:FireClient(player, summary)
return summary
end
local function pluginFunction(Args)
local player = Args[1]
local target = Args[3]
if not target then
return "Please provide a username or team prefix."
end
local lowered = string.lower(target)
if EveryoneAntiAbuse and (lowered == "everyone" or lowered == "all") then
return "Anti-Abuse setting is enabled. Mass demotions are not allowed."
end
if #target < MIN_USERNAME_LENGTH then
return string.format("Username must be at least %d characters long.", MIN_USERNAME_LENGTH)
end
if target:sub(1, 1) == "%" then
local teamName = target:sub(2)
local team = game.Teams:FindFirstChild(teamName)
local victims = {}
if not team then
for _, t in pairs(game.Teams:GetChildren()) do
if string.sub(t.Name, 1, 1):lower() == string.sub(teamName, 1, 1):lower() then
team = t
break
end
end
end
if team then
for _, plr in pairs(game.Players:GetPlayers()) do
if plr.Team == team then
table.insert(victims, plr)
end
end
end
if #victims == 0 then
return "No players found in the specified team."
end
log("DEMOTE", string.format("Team demotion started (%s) - %d users", team.Name, #victims))
local summary = processMultiple(player, victims)
return summary
end
local victims = returnPlayers(player, target)
if not victims or #victims == 0 then
return "Couldn't find player."
end
local summary = processMultiple(player, victims)
return summary
end
local desc = string.format("%s%s %s\n%s", pluginPrefix, pluginName, pluginUsage ~= "" and pluginUsage or "", pluginDescription)
return pluginName, pluginFunction, pluginLevel, pluginPrefix, {pluginName, pluginUsage, pluginDescription}
end
return Plugin
3
API Key
- Visit https://app.panora.cc and copy your API Key.
See API Key - Replace the
API_KEYin the script with your actual API key. - Under the Panora Dashboard > Panora API, whitelist your gameβs Universal Game ID.
See Whitelist
4
Roblox Group
- Set your
GROUP_IDto match the Roblox group linked to your Panora workspace.
See Initial Setup - Configure your group ranks in the
rankstable in ascending order. - Set a cooldown time to avoid rapid promotions (recommended:
20 seconds).
βοΈ Configuration
| Variable | Description | Required |
|---|---|---|
API_KEY | Your Panora API key from app.panora.cc | β |
GROUP_ID | Roblox Group ID linked to your workspace | β |
ranks | An ordered table of your group ranks | β |
COOLDOWN_TIME | Seconds to wait before promoting a user again | β οΈ Recommended |
ranks table:
Copy
local ranks = {
{rankId = 1, rankName = "Member"},
{rankId = 2, rankName = "Moderator"},
{rankId = 3, rankName = "Admin"},
}
