Developer Documentation
Panelr's open plugin system lets developers connect any IPTV panel with an API. Build once, distribute to any Panelr installation.
A Panelr plugin is a PHP class that connects a Panelr installation to an IPTV panel's API. Every IPTV provider uses a panel to manage their streams and subscribers — XtreamUI, custom panels, proprietary systems. Panelr is panel-agnostic by design: instead of building native support for every panel that exists, Panelr uses plugins to bridge that gap.
When a provider installs your plugin, Panelr can automatically create lines, renew subscriptions, sync products, update bouquets, and manage subscribers — all through your panel's API, without the provider ever having to log in manually.
The full lifecycle from development to a client's running installation:
PanelPluginInterface and upload it to your developer account at cloud.panelr.app.To build and distribute Panelr plugins you need a developer account. Login to your exsting Panelr Cloud account at cloud.panelr.app and enable developer access from your account settings. Once enabled, you'll have access to the My Plugins section where you can upload, manage, and sign your plugins.
Create a new PHP file named after your class — for example MyPanelPlugin.php. The filename must match the class name exactly.
<?php
class MyPanelPlugin implements PanelPluginInterface
{
private array $config = [];
public function getName(): string
{
return 'My Panel Plugin';
}
public function getVersion(): string
{
return '1.0.0';
}
public function getCapabilities(): array
{
return ['products', 'activations', 'bouquets'];
}
public function getRequiredConfigFields(): array
{
return [
[
'key' => 'api_url',
'label' => 'Panel API URL',
'type' => 'url',
'required' => true,
'default' => '',
'description' => 'Base URL of your panel API',
],
[
'key' => 'api_key',
'label' => 'API Key',
'type' => 'password',
'required' => true,
'default' => '',
'description' => 'Your panel API key',
],
];
}
public function configure(array $config): void
{
$this->config = $config;
}
public function testConnection(): array
{
$ch = curl_init($this->config['api_url'] . '/ping');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-Api-Key: ' . $this->config['api_key']],
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $code === 200
? ['success' => true, 'message' => 'Connected successfully.']
: ['success' => false, 'message' => 'Could not connect to panel.'];
}
// Implement remaining interface methods...
}
bouquets_update — your clients won't see controls that don't work.
When you sign a plugin for a client, Panelr packages it into a ZIP containing three files. You only provide the PHP file — the other two are generated automatically.
{ClassName}.php — your plugin class fileplugin.json — manifest generated from your plugin settingslicense.json — cryptographic license locked to the target installationMyPanelPlugin.php → class MyPanelPluginEvery plugin must implement all methods of PanelPluginInterface. Every method returns an array containing at minimum a success key. Methods gated behind a capability are only called when that capability is declared in getCapabilities() — but all methods must still be present in your class.
"1.0.0".Returns field definitions Panelr uses to render a configuration form in the admin. Each field is an array with:
key — stored in config JSON, passed back via configure()label — form label shown to the admintype — text, password, url, number, or selectrequired — booleandefault — default valuedescription — help text shown below the fieldoptions — for select type only: ['value' => 'Label', ...]Tests connectivity to the panel API. Called when an admin saves plugin settings.
['success' => true, 'message' => 'Connected successfully.']
['success' => false, 'message' => 'Could not connect to panel.']
Creates a new line on your panel. Panelr passes product_id, bouquet_ids, duration_months, and notes. Return the new line details:
['success' => true, 'data' => [
'panel_user_id' => '1234',
'xtream_username' => 'abc123',
'xtream_password' => 'xyz789',
'expiration_date' => '2027-01-01 00:00:00',
'xtream_host' => 'http://panel.example.com:8080', // optional
'm3u_url' => 'http://...', // optional
]]
Extends an existing line. Panelr passes expiration_date, product_id, duration_months, username, and password. Return the new expiration date:
['success' => true, 'data' => [
'expiration_date' => '2028-01-01 00:00:00',
]]
['success' => true] on success.
Returns current status and details for a line. Required fields: status (active, expired, disabled, or banned) and expiration_date. Return any additional fields your panel provides.
Fetches packages/products from your panel. Required fields per item: product_id, name, duration_months. Optional: connections, credits, panel_description.
bouquet_id, name.$params['bouquets'] contains the array of bouquet IDs to assign.panel_user_id, xtream_username, xtream_password, expiration_date.['success' => true, 'data' => 1500].Declare only the capabilities your panel actually supports. Panelr uses this to show or hide admin controls — undeclared capabilities are never displayed.
| Capability | What it enables |
|---|---|
products |
Sync packages and products from the panel into Panelr |
activations |
Create, renew, and view line details |
terminations |
Permanently cancel a line |
enable_disable |
Temporarily enable or disable a line |
bouquets |
Sync bouquet and channel groups |
bouquets_update |
Update a line's assigned bouquets |
credits |
Display reseller credit balance in the dashboard |
lines |
Bulk import all lines from the panel |
trials |
Enable trial line creation workflow |
Plugin files are scanned automatically on upload. Files that violate these rules are rejected before storage.
curl_* functions for HTTP requests to your panel APIjson_encode, json_decode, urlencode, urldecodedate, time, strtotime, date_createexec, shell_exec, system, passthru, proc_openeval, assert, create_functionfopen, fwrite, file_put_contents, file_get_contentsmysqli_*, new PDOinclude, require$_GET, $_POST, $_SERVER, $_SESSIONecho, print, var_dumpbase64_decode+eval chains, variable variablesEverything after your plugin code is written happens in Panelr Cloud at cloud.panelr.app. This section walks through the full workflow — uploading your plugin, managing it over time, signing it for individual clients, and automating signing via the API.
Everything after your plugin code is written happens in Panelr Cloud at cloud.panelr.app. This section walks through the full workflow — uploading your plugin, managing it over time, signing it for individual clients, and automating signing via the API.
Each plugin row shows:
Click Add Plugin from the My Plugins page to open the upload form. Fill in the plugin metadata and upload your PHP file — Panelr scans it immediately.
The form fields:
getCapabilities() method returns — Panelr validates this during the scan.PanelPluginInterface. The file is scanned for security violations and interface compliance before it's accepted.Click Upload & Scan to submit. If the scan passes, your plugin appears in My Plugins and is ready to sign. If it fails, you'll see specific errors — fix them and re-upload.
Signing is how you issue your plugin to a specific client. Every signed package is cryptographically locked to a single Panelr installation — it cannot be shared or reused on another installation.
Click Sign on any plugin to start the three-step signing flow:
Your client uploads the signed ZIP into their Panelr installation. Panelr verifies the cryptographic signature and file integrity automatically — if anything has been tampered with, the install is rejected. Once installed, they configure the plugin with their panel credentials from their admin dashboard.
For developers distributing to many clients, Panelr provides a signing API that lets you automate the signing process programmatically. Instead of using the web interface for each client, you can sign and download packages via API calls from your own systems.