This guide explains how to install, activate, deactivate, and delete plugins from the admin panel.
Accessing Plugin Management
Navigate to Plugins in the admin sidebar. The page lists all installed plugins with their status.
Required permission: Admin role for viewing, Super-admin for upload/activate/deactivate/delete.
Plugin List
The plugin list shows:
| Column | Description |
|---|---|
| Name | Plugin display name |
| Version | Installed version |
| Provider Type | Unique identifier used for routes and settings |
| Status | Active or Inactive badge |
| Frontend | Whether the plugin includes a frontend bundle |
| Installed | When the plugin was installed |
| Health | Last known health check result |
Uploading a Plugin
- Click Upload Plugin and choose a
.tgzfile (max 50 MB). - The server validates the archive: checks format,
package.jsonmetadata, path traversal, and size limit. - On success, the plugin appears in the list as Inactive.
The plugin archive must contain a package.json with a pokerEnginePlugin field including providerType and displayName.
Activating a Plugin
Click Activate on an inactive plugin. The server:
- Dynamically imports the plugin entry point.
- Calls the plugin’s
register()function. - Sets the plugin to active in the database.
If activation fails (missing register() export, runtime error), an error message is shown.
Deactivating a Plugin
Click Deactivate on an active plugin. The server:
- Checks that no active payment systems depend on this plugin’s provider type.
- Removes all registered hooks, filters, and routes.
- Sets the plugin to inactive (settings are preserved).
If payment systems depend on the plugin, a 409 Conflict error is shown listing the dependent systems. Disable those payment systems first.
Upgrading a Plugin
The Plugins page has no upgrade control, so upgrade through the API below with the new .tgz file:
- Send the file to the upgrade endpoint.
- The server validates the archive (same checks as upload, plus providerType must match).
- The old version is deactivated, the new files are swapped in atomically, and the new version is registered.
- If the upgrade fails, the old version is automatically restored.
- Settings are preserved across upgrades.
Connected clients receive a plugin:updated WebSocket event and automatically reload the plugin’s frontend bundle.
API
POST /api/v1/admin/plugins/:id/upgrade — Super-admin. Multipart .tgz upload (same as install).
Deleting a Plugin
Click Delete on an inactive plugin. A confirmation dialog appears. Deletion:
- Removes the plugin files from disk.
- Deletes the database record (settings are cascade-deleted).
Active plugins cannot be deleted — deactivate first.
Plugin Settings
Plugins that declare configFields in their package metadata show a Settings (gear) button in the actions column. Click it to open the auto-generated settings form.
Supported Field Types
| Type | Control | Notes |
|---|---|---|
text | Text input | Default for unknown types |
password | Password input with show/hide toggle | Encrypted at rest |
number | Number input | Validated server-side |
toggle | On/off switch | Stored as "true" / "false" |
select | Dropdown | Options defined in configFields |
textarea | Multi-line text area | — |
Settings Flow
- Navigate to Plugins → Settings for the plugin.
- Fill in the form. Required fields are marked with a red asterisk.
- Click Save. The server validates required fields and type constraints.
- Plugins can register custom validation via the
plugin:settings:validatefilter hook. - Password-type values are encrypted before storage and decrypted on read.
Settings API
| Method | Path | Permission | Description |
|---|---|---|---|
GET | /api/v1/admin/plugins/:providerType/settings | Admin | Get settings + field definitions |
PUT | /api/v1/admin/plugins/:providerType/settings | Super-admin | Save settings |
GET | /api/v1/config/plugin-settings/:providerType | Authenticated | Public settings (no passwords) |
API Endpoints
| Method | Path | Permission | Description |
|---|---|---|---|
GET | /api/v1/admin/plugins | Admin | List all plugins |
GET | /api/v1/admin/plugins/:id | Admin | Get plugin details |
POST | /api/v1/admin/plugins/upload | Super-admin | Upload plugin .tgz |
POST | /api/v1/admin/plugins/:id/activate | Super-admin | Activate plugin |
POST | /api/v1/admin/plugins/:id/deactivate | Super-admin | Deactivate plugin |
POST | /api/v1/admin/plugins/:id/upgrade | Super-admin | Upgrade plugin with new .tgz |
DELETE | /api/v1/admin/plugins/:id | Super-admin | Delete inactive plugin |
GET | /api/v1/admin/plugins/:providerType/settings | Admin | Get plugin settings |
PUT | /api/v1/admin/plugins/:providerType/settings | Super-admin | Save plugin settings |
POST | /api/v1/admin/plugins/:providerType/health-check | Admin | Trigger on-demand health check |
Plugin Health Checks
Plugins can declare hasHealthCheck: true in their package.json pokerEnginePlugin field and export a healthCheck(registry) function. The engine uses this to monitor plugin operational status.
How it works
- On-demand check: Click the Check Health button (pulse icon) on the Plugins page for any active plugin that declares
hasHealthCheck. - Periodic check: The engine automatically runs health checks every 5 minutes for all loaded plugins with a registered
healthCheckexport. - After activation: A health check runs automatically after a plugin is activated.
- After settings saved: A health check runs automatically after plugin settings are updated.
Health status indicators
The Health column on the Plugins page shows a coloured dot:
| Dot colour | Meaning |
|---|---|
| Grey | No health data yet (never checked) |
| Green | Last check passed (healthy) |
| Red | Last check failed (unhealthy) |
Circuit breaker integration
An unhealthy health check result increments the plugin’s circuit breaker error counter by 10 points. If a plugin reports unhealthy status repeatedly and the counter reaches 50 within a 5-minute window, the circuit breaker triggers and the plugin is automatically deactivated.
Writing a health check
// dist/server/index.js (compiled plugin server entry)
export function register(registry) {
// ... register hooks, routes, etc.
}
export async function healthCheck(registry) {
// Return { healthy: true } or { healthy: false, message: '...' }
try {
await registry.settings.get('api_key'); // example: verify config
return { healthy: true, message: 'All systems operational' };
} catch (err) {
return { healthy: false, message: err.message };
}
}
Safe Mode
Set SAFE_MODE=true in your .env file to boot the server with all plugins disabled. This is useful for diagnosing plugin-related startup failures.
In safe mode:
- No plugins are loaded at startup (both env-based and DB-based plugins are skipped).
- The admin panel is fully accessible — a Safe Mode Active banner on the Plugins page indicates all plugins were skipped at startup.
- You can still activate, deactivate, and manage plugins manually.
Startup Error Isolation
If a plugin fails to load during normal startup (not safe mode), the server:
- Logs the error with the plugin name and source.
- Auto-deactivates the plugin (
isActive=false) and records the error inlastError. - Continues loading remaining plugins without interruption.
This prevents crash loops — a failed plugin won’t retry on the next boot. The Plugins page shows a "Startup failed" badge for auto-deactivated plugins.
Circuit Breaker
The engine monitors runtime errors from plugin hook callbacks. If a plugin produces 50 or more errors within a 5-minute window, it is automatically deactivated to protect platform stability.
When the circuit breaker triggers:
- All plugin hooks, filters, and routes are removed immediately.
- The plugin is marked as inactive in the database with the reason in
lastError. - A
plugin:auto-disabledWebSocket event is broadcast, removing the plugin’s frontend UI instantly. - The Plugins page shows an "Auto-disabled" badge for the plugin.
An administrator must manually re-activate the plugin after investigating the issue.
Related
- Cashier & Payments — payment system configuration
- Settings — platform settings