Plugin API¶
The plugin API lets external FiveM resources extend EasyAdmin's UI at runtime. Plugins register via exports and provide schema trees that EasyAdmin renders using its built-in components.
Why Events, Not Exports?¶
FiveM exports cannot pass functions between resources. When you call
exports['resource'].someExport(fn), the function fn becomes nil on
the receiving end.
The plugin system works around this by using events for handler registration:
- Plugin registration (
RegisterPlugin) passes only a config table — this works fine through exports - Handler registration uses
AddEventHandler— the handler function stays in the plugin's own script environment - Dispatch — EasyAdmin triggers an event, the plugin's handler fires, and responds via a callback
Registration¶
exports.EasyAdmin:RegisterPlugin(config)¶
Register a plugin from your resource's server script only. The server is the source of truth — it stores the plugin and broadcasts it to all clients.
1 2 3 4 5 6 7 8 9 10 11 | |
Declare every permission you gate UI on in permissions. A gate that uses an
undeclared permission hides that nav item, tab or page from every admin. The
ACE name of a permission is always easyadmin.<permission>.
See Creating a Plugin for the full config shape.
Client Handlers¶
EasyAdmin:Plugin:action:<pluginId>:<actionName>¶
Register a client-side handler for render actions and button clicks:
1 2 3 4 5 6 7 | |
| Parameter | Type | Description |
|---|---|---|
data |
table |
Payload from the NUI (may contain context) |
cb |
function(result) |
Callback — call with a schema array or response table |
Return behaviour:
- Call cb({ schema array }) → replaces the current page with the new schema
- Call cb({ ok = true, ... }) → triggers a re-fetch of the original renderAction
Server Handlers¶
EasyAdmin:Plugin:serverAction:<pluginId>:<actionName>¶
Register a server-side handler. Reached by buttons with server = true:
1 2 3 4 5 6 | |
| Parameter | Type | Description |
|---|---|---|
source |
number |
Player server ID — passed as the handler's first argument |
data |
table |
Payload from the NUI |
cb |
function(result) |
Callback — call with a response table |
Read the source argument. Do not rely on the global source variable, which
is not set for this event.
Server handlers must always be permission-guarded. The bridge does not perform automatic permission checks.
Handler Constraints¶
Handlers must call cb within about 500 ms. Dispatch falls back after 500 ms
and the NUI waits 600 ms for server actions, so a slower handler is reported as
no handler registered / no server handler. cb is single-shot: further calls
from the same request are ignored.
Long-running work must be finished before the request (for example cached). When it cannot be, answer first and ask for a refresh once the result is in:
1 | |
See Refreshing an open view for the addressing rules.
Other EasyAdmin Exports¶
These exports exist independently of the plugin system. The tables below are a curated subset for plugin authors, not the full export list.
Permissions and Admin State¶
| Export | Parameters | Description |
|---|---|---|
EasyAdmin:DoesPlayerHavePermission |
player, permission |
Server: pass a player server ID. Client: pass -1 for the local player |
EasyAdmin:DoesPlayerHavePermissionForCategory |
player, prefix |
True if any permission starting with prefix is held |
EasyAdmin:IsPlayerAdmin |
playerId |
True if the player is a known online admin |
EasyAdmin:GetOnlineAdmins |
(none) | Table of online admins keyed by server ID |
EasyAdmin:CanTargetPlayerForModeration |
src, target, immuneMessage? |
false when the target is immune to src |
EasyAdmin:announce |
message, sender? |
Send a global announcement. Returns false for an empty message |
EasyAdmin:getName |
playerId, anonymousDisabled?, identifierEnabled? |
Player name, resolved from cache when possible |
EasyAdmin:isPlayerOnline |
playerId |
Cache-backed online check |
Plugin Views¶
| Export / event | Parameters | Description |
|---|---|---|
EasyAdmin:RefreshPlugin (client) |
pluginId, target?, id?, playerId? |
Re-run one of your views' render action. target is 'page', 'widget' or 'tab'; id is the page view, widget id or tab id. Omit them to refresh every view of the plugin. Only the calling plugin's own views can be refreshed |
EasyAdmin:Plugin:refresh (net event) |
pluginId, target?, id?, playerId? |
The server-side equivalent: TriggerClientEvent('EasyAdmin:Plugin:refresh', src, ...) after handing that client fresh data |
Player Actions¶
| Export | Parameters | Description |
|---|---|---|
EasyAdmin:mutePlayer |
playerId, toggle, source |
Mute or unmute a player |
EasyAdmin:warnPlayer |
source, playerId, reason |
Warn a player (moderator first) |
EasyAdmin:getPlayerWarnings |
playerId |
Number of warnings on record |
Ban Management¶
| Export | Parameters | Description |
|---|---|---|
EasyAdmin:addBan |
playerId, reason, expires, banner |
Add a new ban. playerId may be a server ID or a table of identifiers |
EasyAdmin:unbanPlayer |
banId |
Remove a ban by ID |
EasyAdmin:fetchBan |
banId |
Fetch a ban entry |
EasyAdmin:GetFreshBanId |
(none) | Get the next available ban ID |
EasyAdmin:IsIdentifierBanned |
identifier |
Check if an identifier is banned |
addBan fires the EasyAdmin:addBan event (see below). Called from your own
resource there is no invoking player, so banner is what is recorded as the
moderator.
History, Notes, Reports and Screenshots¶
| Export | Parameters | Description |
|---|---|---|
EasyAdmin:getActionHistory |
identifiers |
Get action history for identifiers |
EasyAdmin:getAdminNotes |
identifiers |
Get admin notes for identifiers |
EasyAdmin:getAllReports |
(none) | Get all active reports |
EasyAdmin:isScreenshotInProgress |
(none) | Check if a screenshot is in progress |
Webhooks¶
| Export | Parameters | Description |
|---|---|---|
EasyAdmin:sendWebhook |
message, options? |
Send a Discord webhook message (see below) |
EasyAdmin:SendWebhookMessage |
webhook, message, feature?, colour?, title?, image? |
Direct access to internal webhook function |
EasyAdmin:isWebhookFeatureExcluded |
feature |
Check if a feature is excluded from webhooks |
sendWebhook(message, options)¶
The recommended entry-point for logging moderation actions from plugins.
Resolves a named webhook convar to its URL and posts a formatted Discord
embed. When ea_botLogChannel is configured, messages are routed through
the Discord bot automatically.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
| Option | Type | Default | Description |
|---|---|---|---|
webhook |
string |
"moderation" |
Named convar ("moderation", "detail", "report") or a direct webhook URL |
feature |
string |
nil |
Feature tag for ea_excludeWebhookFeature filtering |
colour |
number |
16777214 |
Embed colour as decimal |
title |
string |
"EasyAdmin" |
Embed title |
image |
string |
nil |
Image URL for the embed |
Events¶
Listen for these events¶
| Event | Arguments | Description |
|---|---|---|
EasyAdmin:Plugin:registered |
config |
A plugin was registered — use it to initialise client-side state |
EasyAdmin:Plugin:unregistered |
pluginId |
A plugin was removed, usually because its resource stopped |
EasyAdmin:AnnouncementSent |
message, sender? |
An announcement was sent. sender is { name: string, id: number } when available, or nil for external callers (e.g. Discord bot, direct export call) |
EasyAdmin:reportAdded |
report |
A report was filed |
EasyAdmin:reportClaimed |
report |
A report was claimed |
EasyAdmin:reportRemoved |
report |
A report was closed |
EasyAdmin:addBan |
playerId, reason, expires, banner? |
A ban was added |
EasyAdmin:addBan passes positional arguments, not a table. banner is absent
for bans raised automatically from player reports.
EasyAdmin:AnnouncementSent — Forward to other systems¶
Use this event to relay EasyAdmin announcements to other resources (phone apps, logging systems, audit trails, etc.):
1 2 3 4 5 6 | |
EasyAdmin:LogAction — Log an action¶
This is a server-side event you trigger, not one you listen to. It is not a
net event, so fire it from server code with TriggerEvent:
1 2 3 4 5 6 7 8 | |
| Key | Required | Description |
|---|---|---|
action |
Yes | Action type string, stored as-is |
identifiers |
No | Identifiers to attach the entry to. When omitted, the identifiers of playerId are used |
reason |
No | Reason or description |
moderator |
No | Moderator name. Defaults to Console |
moderatorIdents |
No | Moderator identifiers. Defaults to an empty table |
banid |
No | Associated ban ID |
The second argument (playerId) is only needed when identifiers is omitted.
Example¶
1 2 3 4 5 6 7 | |