Open-source .NET 10 SDK for WHM, cPanel and UAPI — multi-tenant, strongly-typed, MIT licensed.
Blurpx.Whm is a complete .NET client for the cPanel & WebHost Manager APIs. It exposes 26 strongly-typed service surfaces and registers itself with Microsoft.Extensions.DependencyInjection via attribute-based discovery.
The library is extracted from a production multi-tenant control-panel codebase and is designed for hosting platforms that talk to many WHM servers from a single set of singleton services.
- Why this library
- Features
- Supported services
- Requirements
- Installation
- Quickstart
- Configuration
- Error handling
- Extending
- Project layout
- Versioning
- Contributing
- Security
- License
The cPanel/WHM JSON API is comprehensive but has rough edges that hand-rolled HttpClient code keeps tripping over:
| Problem | How Blurpx.Whm handles it |
|---|---|
Two response shapes (legacy at JSON root vs. v1 metadata/data envelope), and sending api.version=1 to a legacy endpoint silently breaks it. |
WhmApiCall.ApiVersion is per-call; service implementations set the correct value. |
Some endpoints return null for fields typed as numbers (e.g. suspended_login in listpopswithdisk). |
The deserialization pipeline catches only the null → value type case and lets every other JSON error through. |
| One application typically needs to drive multiple WHM servers. | Services are stateless; a WhmRegion (endpoint + token + SSL setting) is passed per call. |
WHM expects parameters as query?key=value, even for state-changing calls. |
Request DTOs use [WhmParameter("...")] so C# property names stay idiomatic. |
- 26 service surfaces covering Accounts, Backups, CloudLinux, Config, Cron Jobs, Disk Usage, DNS, DNS Zones, Domains, Email, Files, FTP, IPs, Mailing Lists, ModSecurity, MySQL, Packages, PostgreSQL, Redirects, Resellers, Security, Server, Service Manager, SpamAssassin, SSL and User SSL.
- Multi-tenant by design —
WhmRegioncarries hostname, token, timeout and SSL posture per call. - Attribute-based DI —
[WhmRegister(typeof(IFoo))]+services.AddWhmServices(). - Attribute-based parameter mapping —
[WhmParameter("real_api_name")]on request DTOs. - Forgiving JSON pipeline — handles WHM's documented quirks without silencing real bugs.
- Per-call SSL selection — strict for production, permissive for self-signed lab boxes.
- Static
HttpClientreuse — no per-call socket churn, noHttpClientFactoryrequired. - Typed exception ladder —
WhmApiException,WhmCpanelUserNotFoundException,WhmDomainNotFoundException,WhmInvalidDomainException,WhmInvalidEmailAddressException,WhmInvalidUsernameException,WhmPackageNotFoundException.
| Interface | Endpoints |
|---|---|
IWhmAccountService |
createacct, listaccts, accountsummary, suspendacct, unsuspendacct, removeacct, password & quota changes |
IWhmBackupService |
Backup configuration, restore jobs, suspended-account restore |
IWhmCloudLinuxService |
CloudLinux LVE inspection, LVE statistics |
IWhmConfigService |
Tweak settings, basic WHM configuration |
IWhmCronjobService |
cPanel-user cron CRUD |
IWhmDiskUsageService |
Per-account / per-mailbox disk metrics |
IWhmDnsService |
DNS cluster, nameserver health |
IWhmDnsZoneService |
Zone CRUD, record CRUD |
IWhmDomainService |
Addon / subdomain / parked domain management |
IWhmEmailService |
Mailbox CRUD, forwarders, autoresponders |
IWhmFileService |
File manager operations |
IWhmFtpService |
FTP account CRUD |
IWhmIpService |
Shared / dedicated IP allocation |
IWhmMailingListService |
Mailman list CRUD |
IWhmModSecurityService |
ModSecurity rules, deployment, audit log |
IWhmMySqlService |
MySQL user & database CRUD, grants |
IWhmPackageService |
Hosting plan / package CRUD |
IWhmPostgreSqlService |
PostgreSQL user & database CRUD |
IWhmRedirectService |
HTTP redirects |
IWhmResellerService |
Reseller creation, ACL configuration, limits |
IWhmSecurityService |
cPHulk, hotlink protection, IP deny manager |
IWhmServerService |
Server-wide status, version, hostname, license |
IWhmServiceManagerService |
Apache, MySQL, named, exim — start/stop/restart |
IWhmSpamAssassinService |
SpamAssassin configuration |
IWhmSslService |
Server-level SSL certificate management |
IWhmUserSslService |
Per-cPanel-user SSL installation, AutoSSL toggles |
| Runtime | .NET 10.0 or later |
| WHM/cPanel | WHM 88.x and later (legacy + v1 endpoints supported) |
| Authentication | WHM API token (Home › Development › Manage API Tokens) |
Install Blurpx.Whm from NuGet.
dotnet add package Blurpx.WhmInstall-Package Blurpx.Whm<ItemGroup>
<PackageReference Include="Blurpx.Whm" Version="1.0.0" />
</ItemGroup>To work against the source instead — useful when contributing or when you need an unreleased change — clone the repository and add a project reference:
<ItemGroup>
<ProjectReference Include="..\Whm\Blurpx.Whm\Blurpx.Whm.csproj" />
</ItemGroup>| Package | Purpose |
|---|---|
Newtonsoft.Json |
Tolerant deserialization for WHM's loose JSON typing. |
Microsoft.Extensions.DependencyInjection.Abstractions |
IServiceCollection, ServiceLifetime. |
Microsoft.Extensions.Configuration.Abstractions |
Optional IConfiguration resolution in the auto-DI factory. |
Microsoft.Extensions.Logging.Abstractions |
Optional ILogger<T> injection into custom services. |
The package ships with Source Link metadata and a symbols package (.snupkg) on the NuGet symbol server, so consumers can step directly into the library's source while debugging.
using Blurpx.Whm.Core;
using Blurpx.Whm.Core.Extensions;
using Blurpx.Whm.DTOs.Request;
using Blurpx.Whm.Interfaces;
using Microsoft.Extensions.DependencyInjection;
// 1. Compose the service collection.
var services = new ServiceCollection();
services.AddWhmServices();
var provider = services.BuildServiceProvider();
// 2. Describe the WHM server.
var region = new WhmRegion
{
Name = "node-fra-01",
Hostname = "https://node-fra-01.example.com:2087/",
Username = "root",
AccessToken = "WHM_TOKEN",
TimeoutSeconds = 60,
ValidateSslCertificate = true,
};
// 3. Invoke any service.
var accounts = provider.GetRequiredService<IWhmAccountService>();
var created = await accounts.CreateAccountAsync(region, new CreateAccountRequest
{
Username = "acme",
Domain = "acme.example.org",
Password = "Sup3r-Secret-Password",
Plan = "default",
Contact = "billing@acme.example.org",
});WhmRegion is a plain POCO and is the only configuration object the library exposes. Construct it from IConfiguration, from a database row, from a tenant context — wherever your application keeps "which WHM server are we talking to" information.
| Property | Type | Default | Purpose |
|---|---|---|---|
Name |
string |
null |
Logical identifier used in logs and events. |
Hostname |
string |
— | Base URL including scheme and port, e.g. https://server:2087/. |
Username |
string |
— | WHM root or reseller user. |
AccessToken |
string |
— | API token generated through WHM. |
TimeoutSeconds |
int |
60 |
Per-call HTTP timeout. Raise for long operations (transfers, backups). |
ValidateSslCertificate |
bool |
true |
Set to false for lab boxes with self-signed certificates. |
AddWhmServices() scans the executing assembly for [WhmRegister]-decorated classes and registers them against their declared service interface. The default lifetime is Scoped; pass a different ServiceLifetime to the attribute to override per service.
[WhmRegister(typeof(IWhmAccountService), ServiceLifetime.Singleton)]
public sealed class WhmAccountService : WhmBase, IWhmAccountService { /* ... */ }Constructor parameters are resolved from the same IServiceProvider, with first-class support for IConfiguration and ILogger<T>.
The library normalizes WHM's mixed-shape error responses into a typed exception ladder.
| Exception | Raised when |
|---|---|
WhmApiException |
Any HTTP, transport or deserialization failure. Base class for the rest. |
WhmCpanelUserNotFoundException |
Requested cPanel user does not exist on the server. |
WhmDomainNotFoundException |
Domain is unknown to WHM. |
WhmInvalidDomainException |
Domain failed WHM's validation. |
WhmInvalidEmailAddressException |
Email address failed WHM's validation. |
WhmInvalidUsernameException |
cPanel username failed WHM's validation. |
WhmPackageNotFoundException |
Hosting package/plan does not exist. |
Recommended pattern:
try
{
await accounts.SuspendAsync(region, "acme", reason: "non-payment");
}
catch (WhmCpanelUserNotFoundException)
{
// already removed — treat as success
}
catch (WhmApiException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)
{
// token revoked — surface to user
throw;
}
catch (WhmApiException ex)
{
_logger.LogError(ex, "WHM operation failed on {Region}", region.Name);
throw;
}To add support for a WHM endpoint that is not yet covered, follow the same pattern every shipped service uses:
using Blurpx.Whm.Core;
using Blurpx.Whm.Core.Attributes;
using Blurpx.Whm.Core.Constants;
public interface IWhmFooService
{
Task<FooResponse> DoSomethingAsync(WhmRegion region, FooRequest request, CancellationToken cancellationToken = default);
}
[WhmRegister(typeof(IWhmFooService))]
public sealed class WhmFooService : WhmBase, IWhmFooService
{
public Task<FooResponse> DoSomethingAsync(
WhmRegion region,
FooRequest request,
CancellationToken cancellationToken = default)
{
var call = new WhmApiCall
{
Region = region,
Function = "do_something",
ApiVersion = WhmApiVersion.V1, // omit for legacy endpoints
Parameters = WhmParameterConvert.ToDictionary(request),
};
return CallWhmAsync<FooResponse>(call, cancellationToken);
}
}AddWhmServices() will pick up the new class automatically on the next process start.
Blurpx.Whm/
├── Core/
│ ├── WhmBase.cs Shared HTTP + JSON pipeline
│ ├── WhmRegion.cs Endpoint + credentials POCO
│ ├── WhmGlobal.cs Shared static helpers
│ ├── Attributes/
│ │ ├── WhmRegister.cs Marks a service for auto-DI
│ │ └── WhmParameter.cs Maps DTO props to API parameter names
│ ├── Constants/ ApiVersion, Decision, DnsRecordType, Function, Language, Module, Service
│ ├── Converters/ JsonConverter implementations
│ ├── Exceptions/ Typed exception hierarchy (8 types)
│ ├── Extensions/
│ │ ├── WhmServiceCollection.cs services.AddWhmServices()
│ │ └── WhmParameterConvert.cs Reflects DTO → Dictionary<string,string>
│ └── Utility/
├── DTOs/
│ ├── Request/ Per-endpoint request DTOs
│ ├── Response/ Per-endpoint response DTOs
│ └── Common/ Shared response envelopes
├── Interfaces/ 27 IWhm* contracts
└── Services/ 26 concrete implementations
This library follows Semantic Versioning. Backwards-incompatible changes will only land in major releases; new endpoints and new fields on existing DTOs are minor releases.
The pre-1.0 surface is treated as stable inside the Blurpx product line — breaking changes will still be batched and noted in release notes.
Contributions are welcome. The recommended flow:
- Open an issue describing the WHM endpoint, bug, or improvement.
- Fork, branch from
main, and follow the existing service pattern (see Extending). - Keep DTOs strongly-typed; do not widen response types to
objectorJObjectunless WHM's response is genuinely polymorphic. - Match the existing code style (file-scoped copyright header, namespace-scoped
usingdirectives, XML doc comments on public surfaces). - Open a pull request.
There is no test harness committed to this repo yet — verify against a real WHM instance and include a brief note in the PR description.
If you discover a vulnerability, please do not open a public issue. Email security@blurpx.com.tr with details and we will respond within 72 hours.
The library never logs API tokens or passwords. If you are running with ValidateSslCertificate = false in production, please reconsider — it disables the only line of defence against MITM on the WHM control channel.
MIT © Blurpx Teknoloji Yazılım Limited Şirketi
See LICENSE for the full text.