chuckbartowski / cpanel-sdk
PHP SDK for the cPanel and WHM APIs (UAPI, API2, WHM API 1) with typed clients and high-level modules
Requires
- php: >=8.2
- symfony/http-client: ^6.4|^7.0
- symfony/http-client-contracts: ^3.0
Requires (Dev)
- phpunit/phpunit: ^10.5|^11.0
- symfony/config: ^6.4|^7.0
- symfony/dependency-injection: ^6.4|^7.0
- symfony/http-kernel: ^6.4|^7.0
Suggests
- symfony/config: To register CpanelSdkBundle in a Symfony application
- symfony/dependency-injection: To register CpanelSdkBundle in a Symfony application
- symfony/http-kernel: To register CpanelSdkBundle in a Symfony application
README
🖥 cPanel & WHM SDK for PHP
A modern, fully typed PHP SDK for driving cPanel (UAPI + API2) and WHM (API 1).
Email · DNS · MySQL · SSL · FTP · Files · Accounts · Resellers · Packages · AutoSSL · Backups
Installation · Quick Start · API Reference · Error Handling
$cpanel->email()->create('support', 'example.com', 'S3cure!Pass', quotaMb: 250); $whm->accounts()->create('customer1', 'customer1.com', ['plan' => 'starter']); $whm->accounts()->createUserSession('customer1');
Framework-agnostic core — usable from any PHP project, script, or worker — with an optional bundle for first-class Symfony integration. Authenticated with API tokens, typed exceptions, and a comment-free, strictly typed codebase (PHP 8.2+, declare(strict_types=1) everywhere).
Table of Contents
- Features
- Requirements
- Installation
- Quick Start (plain PHP)
- Symfony Integration (optional)
- Architecture
- Usage
- API Reference
- Responses
- Error Handling
- Testing
- Security Notes
- WHMCS module
- License
Features
- Full coverage of the three cPanel API surfaces: UAPI (the modern cPanel API), API2 (legacy but still required for zone editing, subdomains, addon domains, file operations), and WHM API 1 (server administration).
- Framework-agnostic: two plain facades (
Cpanel,Whm) you can instantiate anywhere; only hard dependency issymfony/http-client, a standalone component that works in any PHP project. - Token authentication only — no passwords, no sessions, no cookies. Uses the official
Authorization: cpanel user:token/Authorization: whm user:tokenschemes. - High-level, discoverable modules grouped by domain: email, MySQL, DNS, SSL, files, accounts, resellers, backups, PHP versions, security…
- A single normalized response object (
ApiResponse) regardless of which underlying API answered — you never parsecpanelresultormetadataenvelopes yourself. - Typed exception hierarchy under one marker interface, so you can catch narrowly or broadly.
- Escape hatches everywhere: any endpoint not wrapped by a module remains one method call away.
- Optional Symfony bundle with semantic configuration and autowirable services.
- Fully unit-tested against
MockHttpClient(no network required).
Requirements
| Dependency | Version |
|---|---|
| PHP | >= 8.2 |
| cPanel/WHM | any version supporting API tokens (v64+) |
| Symfony | 6.4 LTS or 7.x — optional, only for the bundle integration |
You will need at least one of:
- a cPanel API token — created in cPanel » Security » Manage API Tokens
- a WHM API token — created in WHM » Development » Manage API Tokens
Installation
The package is published on Packagist:
composer require chuckbartowski/cpanel-sdk
Quick Start (plain PHP)
No framework required — build the clients and go:
use ChuckBartowski\CpanelSdk\Client\CpanelClient; use ChuckBartowski\CpanelSdk\Client\WhmClient; use ChuckBartowski\CpanelSdk\Cpanel; use ChuckBartowski\CpanelSdk\Whm; $cpanel = new Cpanel(new CpanelClient( host: 'server.example.com', username: 'myaccount', token: getenv('CPANEL_API_TOKEN'), port: 2083, )); $cpanel->email()->create('support', 'example.com', 'S3cure!Pass', quotaMb: 250); $cpanel->dns()->addRecord('example.com', 'www', 'A', '203.0.113.10'); $whm = new Whm(new WhmClient( host: 'server.example.com', username: 'root', token: getenv('WHM_API_TOKEN'), port: 2087, )); $whm->accounts()->create('customer1', 'customer1.com', ['plan' => 'starter']);
Client constructor signature (identical for both clients):
new CpanelClient( string $host, string $username, string $token, int $port, // 2083 for cPanel, 2087 for WHM bool $verifySsl = true, float $timeout = 30.0, ?HttpClientInterface $httpClient = null, // inject your own (retries, proxy, mock…) );
Symfony Integration (optional)
A ready-made bundle wires everything into the container. Register it:
// config/bundles.php return [ ChuckBartowski\CpanelSdk\CpanelSdkBundle::class => ['all' => true], ];
Then create config/packages/cpanel_sdk.yaml:
cpanel_sdk: host: '%env(CPANEL_HOST)%' verify_ssl: true timeout: 30 cpanel: username: '%env(CPANEL_USERNAME)%' token: '%env(CPANEL_API_TOKEN)%' port: 2083 whm: username: '%env(WHM_USERNAME)%' token: '%env(WHM_API_TOKEN)%' port: 2087
And the matching environment variables:
# .env.local CPANEL_HOST=server.example.com CPANEL_USERNAME=myaccount CPANEL_API_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX WHM_USERNAME=root WHM_API_TOKEN=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
Configuration reference
| Key | Type | Default | Description |
|---|---|---|---|
host |
string | required | Hostname of the cPanel/WHM server (no scheme, no port) |
verify_ssl |
bool | true |
TLS peer/host verification; disable only for self-signed dev servers |
timeout |
float | 30.0 |
Per-request timeout in seconds |
cpanel.username |
string | '' |
cPanel account name |
cpanel.token |
string | '' |
cPanel API token |
cpanel.port |
int | 2083 |
cPanel TLS port |
whm.username |
string | '' |
WHM user (usually root or a reseller) |
whm.token |
string | '' |
WHM API token |
whm.port |
int | 2087 |
WHM TLS port |
The cpanel and whm sections are independent — configure only the side you need. Calling a client with missing credentials throws an AuthenticationException immediately, before any network request is made.
The bundle reuses your application's http_client service when available (so scoped clients, retry strategies, and profiler integration all apply), and falls back to a native client otherwise.
Architecture
src/
├── CpanelSdkBundle.php Symfony bundle: config tree + service wiring
├── Cpanel.php Facade: entry point for cPanel-level modules
├── Whm.php Facade: entry point for WHM-level modules
├── Client/
│ ├── AbstractClient.php Shared HTTP transport, auth header, error mapping
│ ├── CpanelClient.php uapi() and api2() generic executors
│ └── WhmClient.php call() (WHM API 1) and cpanelUapi() (root proxy)
├── Response/
│ └── ApiResponse.php Immutable, normalized response for all 3 API formats
├── Exception/
│ ├── CpanelSdkExceptionInterface.php
│ ├── ApiException.php API answered but reported a failure
│ ├── AuthenticationException.php
│ └── TransportException.php Network / TLS / timeout / invalid JSON
└── Api/
├── Cpanel/ EmailApi, DomainApi, MysqlApi, FtpApi,
│ SslApi, FileApi, DnsApi, StatsApi
└── Whm/ AccountApi, ResellerApi, PackageApi, DnsZoneApi,
IpApi, SecurityApi, BackupApi, PhpApi,
AutoSslApi, ConfigApi, ServerApi
Design decisions:
- Facade + lazy modules:
Cpanel/Whminstantiate each module on first use and cache it, so the DI container only carries four services. - Modules always validate: every module method calls
ensureSuccess()internally and throwsApiExceptionon failure. If you need to inspect a failed response without an exception, drop down to the client level. - Nothing is sealed off: the clients' generic methods accept any module/function/parameter combination, so a cPanel endpoint added tomorrow is usable today.
Usage
Standalone, instantiate the facades as shown in the Quick Start. In Symfony, both facades are autowirable in controllers, services, commands, and message handlers.
The Cpanel facade
use ChuckBartowski\CpanelSdk\Cpanel; final class MailboxProvisioner { public function __construct(private readonly Cpanel $cpanel) { } public function provision(string $localPart, string $domain, string $password): void { $this->cpanel->email()->create($localPart, $domain, $password, quotaMb: 512); } }
The Whm facade
use ChuckBartowski\CpanelSdk\Whm; final class HostingAccountManager { public function __construct(private readonly Whm $whm) { } public function open(string $username, string $domain): void { $this->whm->accounts()->create($username, $domain, [ 'plan' => 'starter', 'contactemail' => 'billing@example.com', ]); } public function suspendForNonPayment(string $username): void { $this->whm->accounts()->suspend($username, 'unpaid invoice'); } }
Generic calls (escape hatch)
Any endpoint not covered by a module remains reachable:
$cpanel->client()->uapi('Batch', 'strict', ['command' => $commands], 'POST'); $cpanel->client()->api2('Cron', 'listcron'); $whm->client()->call('sethostname', ['hostname' => 'srv2.example.com'], 'POST'); $whm->client()->cpanelUapi('customer1', 'Email', 'list_pops');
cpanelUapi() runs a UAPI function as any cPanel account through the WHM token — the standard pattern for hosting control panels where only the root/reseller token is stored.
API Reference
Every method returns an ApiResponse and throws on failure (see Error Handling). Named arguments are shown where they improve readability.
$cpanel->email() — UAPI Email module.
| Method | Underlying function | Notes |
|---|---|---|
accounts(?string $domain = null) |
list_pops_with_disk |
Includes disk usage per mailbox |
create(string $localPart, string $domain, string $password, int $quotaMb = 0) |
add_pop |
0 = unlimited quota |
delete(string $localPart, string $domain) |
delete_pop |
|
changePassword(string $localPart, string $domain, string $password) |
passwd_pop |
|
setQuota(string $localPart, string $domain, int $quotaMb) |
edit_pop_quota |
|
forwarders(?string $domain = null) |
list_forwarders |
|
addForwarder(string $domain, string $localPart, string $destination) |
add_forwarder |
|
deleteForwarder(string $address, string $forwarder) |
delete_forwarder |
|
mailDirUsage(string $localPart, string $domain) |
get_pop_quota |
$cpanel->email()->accounts('example.com'); $cpanel->email()->create('support', 'example.com', 'S3cure!Pass', quotaMb: 250); $cpanel->email()->addForwarder('example.com', 'contact', 'inbox@elsewhere.com');
Domains
$cpanel->domains() — UAPI DomainInfo + API2 SubDomain / AddonDomain / Park.
| Method | Underlying function |
|---|---|
list() |
UAPI DomainInfo::list_domains |
data(?string $domain = null) |
UAPI domains_data / single_domain_data |
addSubdomain(string $subdomain, string $rootDomain, ?string $documentRoot = null) |
API2 SubDomain::addsubdomain |
deleteSubdomain(string $subdomain, string $rootDomain) |
API2 SubDomain::delsubdomain |
addAddonDomain(string $newDomain, string $subdomain, string $documentRoot) |
API2 AddonDomain::addaddondomain |
deleteAddonDomain(string $domain, string $subdomain) |
API2 AddonDomain::deladdondomain |
park(string $domain) / unpark(string $domain) |
API2 Park |
$cpanel->domains()->addSubdomain('api', 'example.com', 'public_html/api');
MySQL
$cpanel->mysql() — UAPI Mysql module.
| Method | Underlying function |
|---|---|
databases() / users() |
list_databases / list_users |
createDatabase(string $name) / deleteDatabase(string $name) |
create_database / delete_database |
renameDatabase(string $oldName, string $newName) |
rename_database |
createUser(string $name, string $password) / deleteUser(string $name) |
create_user / delete_user |
setPassword(string $user, string $password) |
set_password |
grant(string $user, string $database, string $privileges = 'ALL PRIVILEGES') |
set_privileges_on_database |
revoke(string $user, string $database) |
revoke_access_to_database |
addHost(string $host) |
add_host |
Remember that cPanel prefixes database and user names with the account name (myaccount_app).
$cpanel->mysql()->createDatabase('myaccount_app'); $cpanel->mysql()->createUser('myaccount_app', 'S3cret!'); $cpanel->mysql()->grant('myaccount_app', 'myaccount_app');
FTP
$cpanel->ftp() — UAPI Ftp module: accounts(), create(), delete() (with optional home-dir destruction), changePassword(), setQuota(), setHomeDir().
$cpanel->ftp()->create('deploy', 'S3cret!', homeDir: 'public_html', quotaMb: 0); $cpanel->ftp()->delete('deploy', destroyHomeDir: false);
SSL
$cpanel->ssl() — UAPI SSL module: certificates(), installedHosts(), install(), delete(), generateKey(), generateCsr().
$cpanel->ssl()->install('example.com', $certificatePem, $keyPem, $caBundlePem);
Files
$cpanel->files() — UAPI Fileman for content, API2 Fileman::fileop for filesystem operations: list(), read(), write(), info(), mkdir(), delete(), copy(), move(), chmod(), extract(), emptyTrash().
$cpanel->files()->write('public_html', '.htaccess', $rules); $cpanel->files()->extract('backup.tar.gz', 'public_html'); $cpanel->files()->chmod('public_html/config.php', '0600');
DNS (cPanel zone editor)
$cpanel->dns() — API2 ZoneEdit module. addRecord() automatically maps the value to the right parameter name for the record type (address for A/AAAA, cname for CNAME, txtdata for TXT, exchange for MX…).
$cpanel->dns()->records('example.com', ['type' => 'A']); $cpanel->dns()->addRecord('example.com', 'www', 'A', '203.0.113.10', ttl: 3600); $cpanel->dns()->editRecord('example.com', line: 22, params: ['address' => '203.0.113.11']); $cpanel->dns()->removeRecord('example.com', line: 22);
API2 zone records are addressed by line number in the zone file; always re-fetch records after a mutation before addressing another line.
Stats & quotas
$cpanel->stats() — quota() (UAPI Quota), bars() (UAPI StatsBar, configurable display list), bandwidth() (API2 Stats::getmonthlybandwidth).
WHM — Accounts
$whm->accounts() — the account lifecycle, WHM API 1.
| Method | Underlying function | Notes |
|---|---|---|
list(?string $search = null, string $searchType = 'user') |
listaccts |
searchType: user, domain, owner, ip, package |
summary(string $user) |
accountsummary |
|
create(string $username, string $domain, array $options = []) |
createacct |
options: plan, password, contactemail, quota, … |
remove(string $user, bool $keepDns = false) |
removeacct |
Destructive |
suspend(string $user, string $reason = '') / unsuspend(string $user) |
suspendacct / unsuspendacct |
|
changePassword(string $user, string $password) |
passwd |
|
modify(string $user, array $options) |
modifyacct |
|
changePlan(string $user, string $plan) |
changepackage |
|
domainOwner(string $domain) |
domainuserdata |
|
createUserSession(string $user, string $service = 'cpaneld') |
create_user_session |
One-click SSO URL into the user's cPanel |
bandwidth(?string $user = null, ?string $month = null, ?string $year = null) |
showbw |
Bandwidth usage, optionally filtered |
limitBandwidth(string $user, int $limitMb) |
limitbw |
$session = $whm->accounts()->createUserSession('customer1'); $redirectUrl = $session->data('url');
WHM — Resellers
$whm->resellers() — the full reseller lifecycle for multi-tier hosting.
| Method | Underlying function | Notes |
|---|---|---|
list() |
listresellers |
|
stats(string $reseller) |
resellerstats |
Disk/bandwidth totals across owned accounts |
accounts(string $reseller) |
acctcounts |
Used/limit account counts |
promote(string $user, bool $ownsSelf = false) |
setupreseller |
Turns an existing account into a reseller |
demote(string $user) |
unsetupreseller |
|
setLimits(string $user, array $limits) |
setresellerlimits |
e.g. enable_account_limit, account_limit, diskspace_limit |
setPackageLimit(string $user, string $package, bool $allowed, ?int $number = null) |
setresellerpackagelimit |
Restrict which plans a reseller may sell |
setAcls(string $reseller, array $acls) |
setacls |
Fine-grained privilege grants |
setMainIp(string $user, string $ip) |
setresellermainip |
|
setNameservers(string $user, array $nameservers) |
setresellernameservers |
|
suspendAccounts(string $reseller) / unsuspendAccounts(string $reseller) |
suspendreseller / unsuspendreseller |
Suspends the reseller and all owned accounts |
$whm->resellers()->promote('reseller1'); $whm->resellers()->setLimits('reseller1', ['enable_account_limit' => 1, 'account_limit' => 30]); $whm->resellers()->setPackageLimit('reseller1', 'starter', allowed: true, number: 20);
WHM — Packages
$whm->packages() — list(), create(), update(), delete() around listpkgs / addpkg / editpkg / killpkg.
$whm->packages()->create('starter', ['quota' => 5120, 'bwlimit' => 51200, 'maxaddons' => 1]);
WHM — DNS zones
$whm->dnsZones() — full zone lifecycle: list(), dump(), create(), delete(), addRecord(), editRecord(), removeRecord(), reset().
$whm->dnsZones()->create('customer1.com', '203.0.113.10'); $whm->dnsZones()->addRecord('customer1.com', [ 'name' => 'mail', 'type' => 'A', 'address' => '203.0.113.10', 'ttl' => 3600, ]);
WHM — IP addresses
$whm->ips() — IP pool management for dedicated-IP offers.
| Method | Underlying function |
|---|---|
list() |
listips |
add(string $ip, string $netmask) |
addips |
delete(string $ip) |
delip |
assignToSite(string $domain, string $ip) / assignToUser(string $user, string $ip) |
setsiteip |
usage() |
get_shared_ip |
$whm->ips()->add('203.0.113.25', '255.255.255.0'); $whm->ips()->assignToSite('customer1.com', '203.0.113.25');
WHM — Security (cPHulk)
$whm->security() — brute-force protection management, the bread and butter of hosting support.
| Method | Underlying function |
|---|---|
enableCphulk() / disableCphulk() |
enable_cphulk / disable_cphulk |
whitelist(string $ip, string $comment = '') / blacklist(...) |
create_cphulk_record |
listWhitelist() / listBlacklist() |
read_cphulk_records |
removeFromWhitelist(string $ip) / removeFromBlacklist(string $ip) |
delete_cphulk_record |
unblockBrute(string $ip) |
flush_cphulk_login_history_for_ips |
flushLoginHistory() |
flush_cphulk_login_history |
$whm->security()->unblockBrute('198.51.100.7'); $whm->security()->whitelist('203.0.113.50', 'office VPN');
WHM — Backups & restores
$whm->backups() — backup configuration and the account restore queue.
| Method | Underlying function | Notes |
|---|---|---|
config() / setConfig(array $settings) |
backup_config_get / backup_config_set |
|
users() |
backup_user_list |
Users with backup metadata |
dates() |
backup_date_list |
Available restore points |
userBackups(string $user) |
backup_set_list |
|
queueRestore(string $user, string $restorePoint, array $options = []) |
restore_queue_add_task |
Defaults: keep IP, restore MySQL/subdomains/mail config |
activateRestoreQueue() |
restore_queue_activate |
Starts processing queued restores |
restoreQueueState() |
restore_queue_state |
Poll for progress |
clearCompletedRestores() |
restore_queue_clear_completed_tasks |
$whm->backups()->queueRestore('customer1', '2026-07-20'); $whm->backups()->activateRestoreQueue();
WHM — PHP versions
$whm->php() — MultiPHP management per virtual host.
| Method | Underlying function |
|---|---|
installedVersions() |
php_get_installed_versions |
systemDefault() / setSystemDefault(string $version) |
php_get_system_default_version / php_set_system_default_version |
vhostVersions(string ...$vhosts) |
php_get_vhost_versions |
setVhostVersion(string $version, string ...$vhosts) |
php_set_vhost_versions |
handlers(string $version) / setHandler(string $version, string $handler) |
php_get_handlers / php_set_handler |
Versions use EasyApache identifiers (ea-php83), not bare numbers.
$whm->php()->setVhostVersion('ea-php83', 'example.com', 'shop.example.com');
WHM — SSL & AutoSSL
$whm->autoSsl() — server-wide certificate automation plus manual installs with root privileges.
| Method | Underlying function |
|---|---|
providers() / setProvider(string $provider) |
get_autossl_providers / set_autossl_provider |
checkAllUsers() |
start_autossl_check_for_all_users |
checkUser(string $user) |
start_autossl_check_for_one_user |
enableForUser(string $user) / disableForUser(string $user) |
set_autossl_feature_for_users |
installCertificate(string $domain, string $cert, string $key, ?string $caBundle = null) |
installssl |
certificateInfo(string $domain) |
fetch_ssl_vhosts |
$whm->autoSsl()->setProvider('LetsEncrypt'); $whm->autoSsl()->checkUser('customer1');
WHM — Server configuration
$whm->config() — Tweak Settings and global server preferences.
| Method | Underlying function |
|---|---|
tweakSetting(string $key, string $module = 'Main') |
get_tweaksetting |
setTweakSetting(string $key, string|int $value, string $module = 'Main') |
set_tweaksetting |
updatePreferences() / setUpdatePreferences(array $settings) |
get_update_config / update_updateconf |
hostname() / setHostname(string $hostname) |
gethostname / sethostname |
nameserverConfig() |
nameserverconfig |
$whm->config()->setTweakSetting('maxemailsperhour', 200);
WHM — Server
$whm->server() — version(), hostname(), loadAverage(), serviceStatus(), restartService().
$whm->server()->serviceStatus('httpd'); $whm->server()->restartService('exim');
Responses
All calls return an immutable ApiResponse that normalizes the three wire formats (UAPI envelope, API2 cpanelresult, WHM metadata):
$response = $cpanel->mysql()->databases(); $response->success; // bool $response->data; // mixed — the payload's data section $response->data('acct'); // keyed access with optional default $response->errors; // list<string> $response->messages; // list<string> $response->warnings; // list<string> $response->raw; // the complete decoded JSON payload
data() is null-safe: it returns the default when the payload has no such key or when data is not an array.
Error Handling
All SDK exceptions implement CpanelSdkExceptionInterface, so a single catch covers everything:
| Exception | Thrown when | Extras |
|---|---|---|
ApiException |
The API answered but reported a failure (module methods validate automatically) | getErrors(): array, getRaw(): array |
AuthenticationException |
Credentials are missing, or the server answered HTTP 401/403 | thrown before any request when credentials are empty |
TransportException |
Network error, TLS failure, timeout, or a non-JSON response body | wraps the underlying symfony/http-client exception |
use ChuckBartowski\CpanelSdk\Exception\ApiException; use ChuckBartowski\CpanelSdk\Exception\CpanelSdkExceptionInterface; try { $cpanel->email()->create('support', 'example.com', $password); } catch (ApiException $e) { $this->logger->warning('cPanel rejected the mailbox', ['errors' => $e->getErrors()]); } catch (CpanelSdkExceptionInterface $e) { throw new ProvisioningUnavailableException(previous: $e); }
To inspect a failed response without exceptions, use the client directly — client-level methods return the response as-is:
$response = $cpanel->client()->uapi('Email', 'add_pop', $params, 'POST'); if (!$response->success) { // $response->errors, $response->raw }
Testing
The suite runs entirely offline against MockHttpClient:
composer install vendor/bin/phpunit
To test your own services, inject a CpanelClient/WhmClient built with a mock:
use ChuckBartowski\CpanelSdk\Client\CpanelClient; use ChuckBartowski\CpanelSdk\Cpanel; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\JsonMockResponse; $http = new MockHttpClient(new JsonMockResponse(['status' => 1, 'data' => []])); $cpanel = new Cpanel(new CpanelClient('host', 'user', 'token', 2083, true, 30.0, $http));
Security Notes
- API tokens are passed with
#[\SensitiveParameter], so they never appear in stack traces. - Keep tokens in
.env.localor your secret vault — never commit them. - Scope WHM tokens to the minimal privilege set in WHM » Manage API Tokens (e.g. deny
Everything, allow only account functions). - Leave
verify_ssl: truein production; the option exists solely for self-signed development servers. removeacctanddelete_ftp destroy=1are irreversible — gate them behind confirmation flows in your application.
WHMCS module
A ready-to-use WHMCS provisioning module ships in whmcs/modules/servers/cpanelsdk/. It automates cPanel account provisioning through WHM using this SDK — create, suspend, unsuspend, terminate, change password, change package, and one-click SSO into cPanel.
Install
composer require chuckbartowski/cpanel-sdkin your WHMCS root (so the SDK is autoloaded).- Copy the
cpanelsdkfolder into<whmcs>/modules/servers/. - In WHMCS, add a server (System Settings » Servers) with Type: cPanel (SDK), the WHM hostname, username
root, and your WHM API token in the Access Hash field. - Point a product at the server and set the Package config option to the WHM plan name.
| Operation | WHM function used |
|---|---|
| Create / Suspend / Unsuspend / Terminate | createacct / suspendacct / unsuspendacct / removeacct |
| Change password / package | passwd / changepackage |
| One-click login | create_user_session |
License
MIT