Skip to content

API Tokens

An API token is a credential a program holds. It lets a WHMCS install, a provisioning script or a monitoring probe call CorePanel’s JSON-RPC API without a browser and without anybody’s password.

Until tokens existed the API authenticated exactly one thing — an administrator’s session cookie — so every automation story ended at the same wall. A token is the way past it.

Issuing tokens requires CorePanel Pro or Business. Listing and revoking them work on every edition.

Server → API tokens lists every token this organisation has, revoked ones included.

The API tokens page: a table with a row per token showing its name with the public prefix beneath it, the scopes as coloured chips, when it was last used and from which address, its expiry and an Active or Revoked status. A "Create token" button sits in the header. The last row is a revoked token, greyed out and without a revoke action.

The page is available on every edition, and only super-administrators reach it.

From the panel, Create token asks for three things: a name, the scopes, and an optional expiry. Scopes are fixed for the life of the token, so this dialog is the only moment you get to choose them.

The credential appears once, immediately after:

The reveal dialog over the API tokens page: a heading reading "Copy this token now", the full credential in a monospace field with a copy button, the token's prefix and scopes below it, a warning that it is sent as a bearer token and acts on the whole server, and a single "I have copied it" button.

That dialog closes on the button and on nothing else — no click outside, no Escape. It is the only appearance of the credential in its readable form, and the only remedy for losing it is revoking the token and creating another.

From the command line:

Terminal window
corepanel api-token create "WHMCS production" --scope provisioning
Token "WHMCS production" created.
cpk_7f3k9m2xq4bt_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2
This is the only time it will be shown. Copy it now.
id: 1
prefix: 7f3k9m2xq4bt
scopes: provisioning
expires: never

The part before the last underscore (cpk_7f3k9m2xq4bt) is the prefix. It is public: it identifies the token in the panel, in the CLI and in log lines, and it is safe to quote in a support conversation. The rest is the secret.

Send it as a bearer token to the panel’s JSON-RPC endpoint:

Terminal window
curl https://panel.example.com/api/rpc \
-H "Authorization: Bearer cpk_7f3k9m2xq4bt_a1b2c3d4…" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"cp.ListAccounts","params":{}}'

A request that carries both a bearer token and a session cookie is treated as the token’s — which matters if you are testing an integration from a browser tab where you are also signed in. The request does what it says it does, bounded by the token’s scopes rather than by your own session.

Every token carries one or more scopes, chosen when it is created and fixed for its lifetime. To change them, create a new token and revoke the old one.

ScopeWhat it allows
readonlyList and read. Safe for monitoring.
provisioningCreate accounts, suspend and unsuspend them, change packages and passwords. Implies readonly.
terminateDelete accounts.

terminate is separate on purpose, and it is worth using that way: a hosting provider can let dunning run unattended with a provisioning token while cancellations stay behind a human, by simply not granting the scope that destroys data.

A token reaches a fixed list of methods and nothing else. The list is not “everything an administrator can do minus the dangerous parts” — it is an explicit set, and anything absent is refused whatever scopes the token holds.

MethodScope required
cp.getCorePanelDetailsreadonly
cp.GetCoreCapabilitiesreadonly
cp.ListAccountsreadonly
cp.GetAccountreadonly
cp.ListAccountDomainsreadonly
cp.ListPackagesreadonly
cp.CreateAccountprovisioning
cp.UpdateAccountprovisioning
cp.UpdateAccountPasswordprovisioning
cp.SuspendAccountprovisioning
cp.UnsuspendAccountprovisioning
cp.CreateAccountSessionprovisioning
cp.DeleteAccountterminate

The host firewall, the WAF, the MySQL console, backups, application environment variables and token management itself are unreachable by any token. A token cannot create another token, which is what stops a leaked credential from minting itself a wider one.

Signing a customer in from your billing system

Section titled “Signing a customer in from your billing system”

cp.CreateAccountSession is the one method that does not read or write an account — it produces a link that signs the customer in. It is what a “Log in to your hosting” button in a billing area calls: your system asks for a link, then redirects the browser to it, and the customer arrives in their panel having typed nothing.

{"jsonrpc":"2.0","id":1,"method":"cp.CreateAccountSession",
"params":{"user":"acmecorp","client_ip":"203.0.113.44"}}

user is the account — its username, any domain it owns, or its id. client_ip is optional: give it the address of the browser you are about to redirect and the link will only work from there. It must be an IP address — anything else is refused rather than ignored, so a link you asked to be bound is never quietly minted unbound. The answer carries the URL to send them to:

{"url":"https://panel.example.com/login?ott=…","token":"",
"user":"acmecorp","account_id":42,"expires_at":"2026-08-10T18:04:00Z"}

Three properties are worth knowing, because they decide how you use it:

  • It lasts sixty seconds. It has to survive a redirect and nothing else. Ask for the link at the moment the customer clicks, never in advance.
  • It works exactly once. The server destroys it the first time it is presented, so the copy left in a browser history or a Referer header opens nothing. The panel also strips it from the address bar before using it.
  • It is checked again on arrival. An account suspended in the seconds between minting and use cannot get in — the link does not outlive the authorisation behind it.

If the server has no hostname recorded, url comes back empty and you build your own from token; the path is /login?ott=<token> on the panel’s address.

A token belongs to the seller — the hosting organisation — not to the administrator who created it. Removing that administrator does not affect it. This is deliberate: an integration that provisions a hosting provider’s customers has to outlive whoever set it up.

In the audit trail a token names itself rather than a person. An account suspended by a billing run is recorded as token 7f3k9m2xq4bt (seller #1), never as the administrator who created the credential — so an operator reading the log can tell an automated action from a human one.

Tokens do not expire unless you say so. That is the right default for a billing integration: the alternative is provisioning that breaks on a date nobody wrote down.

Terminal window
# Expires at the end of 2026-12-31
corepanel api-token create "status page" --scope readonly --expires 2026-12-31

Revoking takes effect immediately, from the panel (the Revoke action on the row) or from the command line:

Terminal window
corepanel api-token list
corepanel api-token revoke 4

The row is kept rather than deleted, so a token named in an old log line can still be resolved to what it was. Revoking a token that is already revoked succeeds — the command means “make sure this cannot be used”.

An expired card, a network partition, a grace window that ran out — a server can drop to Personal while integrations are running against it. CorePanel is deliberate about what that does:

  • Existing tokens keep authenticating. A licence that lapses at 3 a.m. does not stop a hosting provider’s provisioning.
  • Issuing a new token is refused until the licence is restored.
  • Revoking always works, on every edition.
  • Individual operations degrade on their own terms. Suspension, for instance, requires Business — so a lapsed server keeps answering cp.ListAccounts and refuses cp.SuspendAccount with a clear reason, rather than failing everything at once.

The effect is that usage reporting and reads keep working while the paid operations stop, with an error an operator can read in their integration’s activity log.

  • Treat a token like a password. It is not scoped to one account: within its method list it acts on the whole server.
  • Use one token per integration. They are free to create, and revoking one then costs you exactly that integration instead of all of them.
  • Grant the narrowest scope that works. A monitoring probe needs readonly; almost nothing needs terminate.
  • Rotate by creating first. Create the replacement, move the integration over, then revoke the old token — a token’s scopes cannot be edited in place.