Commands#
Admin Menu registers two chat commands, three keybinds and two console commands. Every action behind them is checked against the player's permissions on the server.
Command | Where | Description |
|---|---|---|
| In game | Opens or closes the Admin Panel. With no account, it opens on registration — the way new staff sign up. The name is |
| In game | Opens the Report Center for any player. The name is |
| Key | Opens the Admin Panel — framework admins and approved accounts only; silent for everybody else. |
| Key | Toggles noclip ( |
| Key | Opens Fast Actions. |
| Server console | Whether Cloudflare TURN is on, the servers it is using, and when their credentials expire. |
| Server console | Fetches fresh Cloudflare TURN credentials now. |
The three keys are defaults from Config.Shortcuts; each staff member can rebind their own in the Profile.
Client Exports#
For opening the menus from your own scripts — a radial menu, a phone app, a HUD button — and for asking what state they are in.
Menus and windows
local open = exports['qs-adminmenu']:IsAdminMenuOpen()
local fastOpen = exports['qs-adminmenu']:IsFastActionMenuOpen()
exports['qs-adminmenu']:ToggleFastActionMenu()
-- The players' Report Center
exports['qs-adminmenu']:OpenPlayerReports()
exports['qs-adminmenu']:ClosePlayerReports()Useful to stop your own UI opening on top of the panel, or to put a "Report" button in a phone or radial menu.
Noclip and spectate
local flying = exports['qs-adminmenu']:IsNoclipEnabled()
exports['qs-adminmenu']:SetNoclipEnabled(false) -- returns the new state
exports['qs-adminmenu']:ExitSpectate()SetNoclipEnabled acts on the local player without checking their permissions — call it only from your own code, for example to drop a staff member out of noclip when a cutscene starts.
Shortcuts
local keys = exports['qs-adminmenu']:GetShortcuts()
-- { openMenu = 'F5', noclip = 'PAGE_DOWN', fastAction = 'DELETE' }
local defaults = exports['qs-adminmenu']:GetDefaultShortcuts()
local allowed = exports['qs-adminmenu']:GetSupportedShortcutKeys()
-- { 'DELETE', 'F10', 'F5', 'F6', 'F7', 'F8', 'F9', 'PAGE_DOWN' }
local result = exports['qs-adminmenu']:UpdateShortcuts({
openMenu = 'F6',
noclip = 'F7',
fastAction = 'F8',
})
-- { ok = true|false, err = nil|'invalid_shortcut', shortcuts = {...} }UpdateShortcuts needs all three keys, each from the supported list. The choice is saved on that player's PC.
Preferences
local prefs = exports['qs-adminmenu']:GetPreferences()
-- { fastActionPosition = 'right-center' }
local defaults = exports['qs-adminmenu']:GetDefaultPreferences()
local result = exports['qs-adminmenu']:UpdatePreferences({
fastActionPosition = 'left-bottom',
})
-- { ok = true|false, err = nil|string, preferences = {...} }Positions: left-top, left-center, left-bottom, right-top, right-center, right-bottom.
Server Exports#
How an anticheat, a Discord bot or your own scripts moderate through Admin Menu, so every warn, kick and ban lands in the same ban list, the same logs and the same Discord channels as one made from the panel. Actions made through an export are recorded as coming from console.
WarnPlayer · KickPlayer
local ok, err = exports['qs-adminmenu']:WarnPlayer(source, 'Mic spam')
local ok, err = exports['qs-adminmenu']:KickPlayer(source, 'AFK in a restricted zone')The player sees the full-screen notice with the reason, then the action is applied.
BanPlayer
-- durationSeconds: nil or 0 = permanent, otherwise 60 seconds to 10 years
local ok, banId = exports['qs-adminmenu']:BanPlayer(source, 'Aimbot detected', 7 * 24 * 3600)
-- ok = false → banId holds the error, e.g. 'invalid_duration'Bans an online player with every identifier and hardware token they have, and drops them with the ban message.
BanIdentifiers
local ok, banId = exports['qs-adminmenu']:BanIdentifiers(
{ 'license:xxxxxxxx', 'discord:123456789012345678' },
'Chargeback',
nil, -- permanent
'PlayerName' -- optional, shown in the Bans page
)Bans somebody who is offline. If any of those identifiers is online right now, that player is dropped.
UnbanPlayer · IsPlayerBanned
local ok, err = exports['qs-adminmenu']:UnbanPlayer(banId, 'Appeal accepted')
local banned = exports['qs-adminmenu']:IsPlayerBanned(source)GetPlayerGroup · GetAdminRole
local group = exports['qs-adminmenu']:GetPlayerGroup(source)
-- the framework group: 'user', 'admin', 'superadmin'...
local role = exports['qs-adminmenu']:GetAdminRole(source)
-- { name = 'ADMIN', label = 'ADMIN', priority = 700 }, or nil when they have no approved accountCompare priority rather than the name to keep working when you rename roles.
Server Events#
Fired for every warn, kick, ban and unban — from the panel, an export or anywhere else. They are server-side only: listen with AddEventHandler, not RegisterNetEvent.
Event | Data |
|---|---|
|
|
|
|
|
|
|
|
admin is the staff member's server id, or 0 when the action came from the console or an export. target is nil for a ban by identifiers; duration (seconds) and expiresAt (unix time) are nil for a permanent ban.
AddEventHandler('qs-adminmenu:playerBanned', function(data)
print(('%s banned %s (#%s): %s'):format(data.adminName, data.targetName, data.banId, data.reason))
end)About the Errors#
Exports that can refuse return false and a short key rather than a sentence — invalid_duration, player_not_found, bans_unavailable. Log the key in your own script; the matching sentence in every language is in locales/. Common Errors explains the ones you are likely to meet.



