Overview
Commerce's provisioning system is fully pluggable. To support a new hosting panel, create a single PHP class in app/Provisioning/Modules/ that implements ProvisioningModule. The registry discovers it automatically — no migration, no config key, no service provider registration needed.
Step 1 — Create the Module File
app/Provisioning/Modules/MyProviderModule.php
The filename does not need to match the module ID, but it is conventional to keep them aligned.
Step 2 — Implement the Interface
<?php
namespace App\Provisioning\Modules;
use App\Contracts\ProvisioningModule;
use App\Models\Server;
use App\Models\Service;
use App\Provisioning\ProvisioningResult;
class MyProviderModule implements ProvisioningModule
{
public static function moduleId(): string
{
return 'myprovider'; // stored in servers.type
}
public static function moduleLabel(): string
{
return 'My Provider Panel';
}
public static function moduleDescription(): string
{
return 'Provisions accounts on My Provider Panel via REST API.';
}
public static function moduleFields(): array
{
return [
['name' => 'api_url', 'label' => 'API URL', 'type' => 'text', 'placeholder' => 'https://panel.example.com', 'required' => true, 'secret' => false],
['name' => 'api_token', 'label' => 'API Token', 'type' => 'password', 'placeholder' => '', 'required' => true, 'secret' => true],
];
}
public function createAccount(Service $service): ProvisioningResult
{
// Call panel API, return success or failure
}
public function suspendAccount(Service $service): ProvisioningResult { ... }
public function unsuspendAccount(Service $service): ProvisioningResult { ... }
public function terminateAccount(Service $service): ProvisioningResult { ... }
public function getAccountInfo(Service $service): ProvisioningResult { ... }
public function testConnection(Server $server): ProvisioningResult
{
// Lightweight auth check — return success/failure
}
}
Required Methods Reference
Static Methods
| Method | Return | Description |
|---|---|---|
moduleId() |
string |
Unique ID stored in servers.type. Use lowercase, no spaces. |
moduleLabel() |
string |
Display name shown on the server form's module picker. |
moduleDescription() |
string |
Short description shown below the module card. |
moduleFields() |
array |
Credential field definitions (see below). |
Instance Methods
| Method | Parameters | Description |
|---|---|---|
createAccount |
Service $service |
Create account on panel; store panel_account_id on service. |
suspendAccount |
Service $service |
Suspend the panel account. |
unsuspendAccount |
Service $service |
Unsuspend the panel account. |
terminateAccount |
Service $service |
Delete the panel account permanently. |
getAccountInfo |
Service $service |
Fetch current account state from panel. |
testConnection |
Server $server |
Verify credentials; return success/failure. |
Field Definition Keys
| Key | Type | Description |
|---|---|---|
name |
string | Key used to store/read from servers.credentials |
label |
string | Label shown on the form |
type |
string | text, password, select |
placeholder |
string | Input placeholder |
required |
bool | Fail validation if blank on create |
secret |
bool | If true: masked on edit, blank submit = keep existing value |
Reading Credentials
Inside any instance method, read credentials like this:
$credentials = $service->server->credentials;
$apiUrl = $credentials['api_url'];
$apiToken = $credentials['api_token'];
Returning Results
return ProvisioningResult::success('Account created.', ['panel_account_id' => $id]);
return ProvisioningResult::failure('API returned 401 Unauthorized.');
On success, data in the second argument is merged into the service record and written to the provisioning log. On failure, the error string is logged and the job retries.
No Restart Required
Commerce resolves modules at runtime. After deploying the file, clear the opcache and the module appears in the Admin → Servers → module picker immediately.