Billing integrations: WHMCS, Blesta and WiseCP

Last updated

Jabali Panel has provisioning modules for three billing systems: WHMCS, Blesta and WiseCP. They are in the jabali-billing-modules repository on GitHub, under the same AGPL-3.0 licence as the panel. When a customer orders, upgrades, stops paying or cancels, the billing system calls the panel and the hosting account changes to match.

Supported billing systems

Billing systemVersionInstall folderSetup guide
WHMCS8.xmodules/servers/jabali/WHMCS module
Blesta5.xcomponents/modules/jabali/Blesta module
WiseCP3.xcoremio/modules/Servers/Jabali/WiseCP module

All three need PHP 7.4 or newer with the curl and json extensions on the billing server.

How the modules talk to the panel

The modules call the panel’s Automation API under /api/v1/automation/. Every request is signed with HMAC-SHA256 using an automation token. The billing system never stores a panel admin password, and there is no login session to expire. All three modules ship the same PHP API client, so signing, retries and error messages are identical.

  • Port. The API answers over HTTPS on :8443. Some billing hosts block outbound 8443 (CSF’s default TCP_OUT does). For them, turn on Also serve the API on port 443 on the panel’s Server API Access page and use port 443 in the billing system. Port 443 serves only the automation routes.
  • Certificate. The panel must present a browser-trusted certificate on that port. The modules have no option to skip certificate checks.
  • Clock. The request timestamp must be within 5 minutes of the panel’s clock, and no more than 30 seconds ahead of it. Keep the billing server and the panel on NTP.
  • Replay protection. The panel accepts each signature once. When a module retries a request, it signs it again with a new timestamp.

1. Create an automation token

Open Server API Access (/jabali-admin/automation) in the admin panel and click Create token. Name the token after the billing system, pick the scopes below and click Generate. The secret is shown once, as a 64-character hex string. Paste it into the billing system straight away: the panel keeps it encrypted and never shows it again. Make sure Writes enabled is on for the token.

From the command line:

jabali automation-token mint whmcs \
  --scope read:status --scope read:users --scope read:packages \
  --scope write:users --scope write:domains --scope delete:users
ScopeWhat the modules use it for
read:statusTest Connection
read:usersFinding accounts; disk and bandwidth usage
read:packagesThe package dropdown in product settings
write:usersCreate, suspend, unsuspend, change password, change package, one-click login
write:domainsCreating the order’s domain together with the account
delete:usersTerminate or cancel. Leave it out if accounts should only ever be suspended.
assert:domain_ownershipOptional. The new account’s domain is verified at once instead of waiting for DNS proof.

write:domains is required for orders with a domain. All three modules send the order’s domain when they create the account. If the token lacks write:domains, the panel rejects the create with 403 scope_denied. Test Connection does not catch this: it confirms the token works and lists the panel’s actions, but does not check that the token holds every scope the modules need.

assert:domain_ownership lets the billing system vouch that its customer owns the domain. Without it, the domain waits for DNS proof of ownership, like a domain a customer adds in the panel. write:* does not include this scope; grant it only to a billing system you trust.

Use one token per billing system, so you can revoke one without touching the others. A token with write scopes can change any non-admin account on the server, so store the secret like a root password. Revoke a token on the same page or with jabali automation-token revoke <name>. It stops working on its next request.

2. Install the module

Each module installs by copying one folder into the billing system. The steps for each system are in its guide: WHMCS, Blesta, WiseCP. Copy the whole folder: each module loads its API client from its own lib/ subfolder.

3. Add the panel as a server

Every billing system asks for the same four values:

Billing fieldValue
HostnameThe panel hostname, e.g. panel.example.com
Username / Token IDThe automation token’s ID
Password / Token secretThe automation token’s secret
Port8443, or 443 if you turned on the port 443 option

Then run the connection test. It reports the actions the panel offers. “No write capabilities advertised” means the panel is older than the billing endpoints. Upgrade it.

4. Map products to packages

Each billing product points at a Jabali hosting package. The package sets the account’s limits; see Hosting Packages. With read:packages, the product settings show a dropdown of the panel’s packages. Without it, paste the package ID (a 26-character ULID) into the manual override field. The package is applied when the account is created and again on upgrade or downgrade.

What each billing action does

Billing actionEffect on the panelEndpointScope
Test connectionChecks the token and lists the panel’s actionsGET /automation/status, GET /automation/capabilitiesread:status
CreateCreates the user on the product’s package and creates the order’s domainPOST /automation/userswrite:users, write:domains
SuspendRuns the same suspend as the admin panel: login blocked, sessions ended, domains disabled, Docker apps stopped, SSH and SFTP lockedPOST /automation/users/:id/disablewrite:users
UnsuspendReverses the suspendPOST /automation/users/:id/enablewrite:users
Change passwordSets the customer’s panel passwordPOST /automation/users/:id/passwordwrite:users
Change packageMoves the account to the new packagePUT /automation/users/:id/packagewrite:users
One-click loginReturns a single-use login link that expires after 5 minutesPOST /automation/users/:id/login-tokenwrite:users
UsageReads disk and bandwidth used and quotaGET /automation/users/:id/usageread:users
Terminate / cancelDeletes the account and its domainsDELETE /automation/users/:iddelete:users

Some things hold for every module:

  • Admin accounts are out of reach. The API never creates an admin. It refuses to suspend, delete, change the password of, or create a login link for one.
  • Creating an account is safe to retry. If the email and username already belong to the same account, the panel answers with that account’s ID instead of creating a second one.
  • Writes are limited to 30 a minute per token, with bursts of up to 10. Spread out bulk jobs, or give each billing server its own token.
  • Every write is audited under the token’s ID in the Audit Log. Creating, suspending or deleting an account also sends a panel notification.

How accounts are matched

The panel identifies an account by its username. Email is not unique: one billing client can own several hosting accounts under the same email address. Creating an account with a new username and an existing email makes a second account. Only a username that is already taken returns 409 conflict.

When an account is created, the module saves the panel’s user ID (a 26-character ULID) and uses it for every later action. If the ID is missing, the module falls back to the username, and accepts an email match only when exactly one account has that email.

Billing systemWhere the panel user ID is kept
WHMCSThe product custom field jabali_user_id
BlestaThe service fields jabali_user_id, jabali_username and jabali_domain
WiseCPThe order’s creation info, editable as Jabali User ID in the admin service view

When the panel lacks an action

When a module connects, it calls GET /automation/capabilities to see which actions the panel offers. If an action is missing, usually because the panel is older than that endpoint, the module returns a clear message instead of failing halfway through provisioning. Suspend, unsuspend and the connection test work on any current Jabali Panel.

Troubleshooting

SymptomCause and fix
Create fails with 403 scope_denied: “creating a domain requires the write:domains scope”The token lacks write:domains. Create a token with the full scope list above and update the server’s credentials.
scope_denied on another actionThe token lacks that action’s scope. Check the scope table above.
401 with “check NTP”The clocks on the billing server and the panel differ by more than 5 minutes. Sync both with NTP.
401 “replay detected”The same signed request reached the panel twice. The module signs every retry again, so a repeat usually means two cron runs overlapping.
429 rate_limitedMore than 30 writes a minute on one token. Spread out the job or use a token per billing server.
Connection times outThe billing host’s outbound firewall blocks 8443. Turn on the port 443 option and set the server port to 443.
TLS or certificate errorThe panel is not presenting a trusted certificate on that port. See Panel Certificate.
Package dropdown is emptyThe token lacks read:packages. Add it, or paste the package ID into the override field.
”panel does not support X yet”The panel is older than that endpoint. Upgrade the panel.
Login link opens the sign-in pageThe panel predates one-click login. Upgrade the panel.

Frequently asked questions

Which billing systems work with Jabali Panel?
WHMCS 8.x, Blesta 5.x and WiseCP 3.x. Each has a provisioning module in the jabali-billing-modules repository on GitHub. All three use the same signed API client, so they behave the same way and report errors the same way.
Are the Jabali Panel billing modules free?
Yes. The modules are open source under AGPL-3.0, the same licence as Jabali Panel. There is no per-account or per-server fee.
Does the billing system store a panel admin password?
No. The modules sign each request with an automation token that you create on the panel's Server API Access page. The token's scopes limit what it can do, it cannot touch admin accounts, and you can revoke it at any time without changing any password.
Which scopes does the automation token need?
read:status, read:users, read:packages, write:users and write:domains, plus delete:users if the billing system should delete accounts on termination. The modules send the order's domain when they create an account, so without write:domains account creation fails with 403 scope_denied.
Can customers log in to Jabali Panel from the billing client area?
Yes. The login button in each module asks the panel for a single-use login link that expires after 5 minutes and opens the customer's panel dashboard without a password prompt.
What if the billing server cannot reach port 8443?
Turn on 'Also serve the API on port 443' on the panel's Server API Access page and set the server port to 443 in the billing system. Only the signed /api/v1/automation/ routes are served on 443; the panel itself stays on 8443.