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 Promote Command
Panora Promote Command
PanoraPromote.lua
Copy
--[[
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π¦ Basic Admin Essentials Plugin β Promote 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 promote 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 promotions
β’ WEBHOOK_URL β Optional; External webhook for promotion logs
β’ MIN_USERNAME_LENGTH β Optional; minimum username length to promote
β’ EveryoneAntiAbuse β Optional; prevents non-Everyone rank promotion
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 = "Promote 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 recentPromotions = {}
local function log(tag, ...)
print(string.format("[%s]", tag), ...)
end
local function findNextRank(currentRank)
return GroupServiceModule.getNextRank(currentRank, GROUP_ID)
end
local function processPromotion(player, target)
log("PROMOTE", "Processing", target.Name)
if player.UserId == target.UserId then
log("DEBUG", "Skipped self-promotion for", target.Name)
return string.format("%s - Skipped (Cannot promote self)", target.Name)
end
local last = recentPromotions[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 nextRank = findNextRank(currentRank)
if not nextRank then
log("DEBUG", string.format("%s already at max rank", target.Name))
return string.format("%s - Already at highest rank", target.Name)
end
local rankData = {
rankerName = player.Name,
rankerId = player.UserId,
rankeeName = target.Name,
rankeeId = target.UserId,
newRankId = nextRank.Rank,
oldRankName = currentRoleName,
command = "promote | BAE Integration",
prefix = Prefix,
webhookUrl = WEBHOOK_URL
}
local success, message = PanoraAPI.rankUser(BASE_URL, API_KEY, rankData)
if success then
recentPromotions[target.UserId] = os.time()
log("PANORA", string.format("Promotion succeeded for %s (%s)", target.Name, message))
return string.format("%s - Success", target.Name)
else
log("PANORA", string.format("Promotion 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 = processPromotion(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 promotions 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("PROMOTE", string.format("Team promotion 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"},
}
