API Authentication and Permissions
How a key is issued, how it travels on a request, and how its permissions decide what it may reach.
Overview
Every credentialed call carries an API key and nothing else. There are no sessions and no cookies, so a call behaves the same from a server, a laptop or a browser tab.
A key holds three things: the surface it belongs to, the list of permissions it was granted, and a request budget per minute. Those three are checked in that order on every request, and the first one that says no ends the call.
The key itself is never stored. What the installation keeps is a hash of it plus the first few characters for display, so a lost key cannot be recovered from the panel. It can only be replaced.
Prerequisites
- Panel access to issue an admin key, or a customer account to issue a client key.
- A place to store the key that is not your source tree.
Walkthrough
Issue a Key
- For the admin surface, open Settings → API Credentials in the panel and create a credential.
- For the client surface, the customer creates their own under API Credentials in their account, at
/api-credentials. - Copy the key from the confirmation. It is shown once and never again.
Grant Permissions
- Tick the actions the key needs. Each checkbox is one
Group/Actionpair, which is the same name the endpoint documents. - Grant the narrowest set that does the job. A key that only reads invoices cannot be turned against your clients.
- Optionally raise or lower the per-minute budget for that one key; empty means the installation default.
Send It and Verify
- Put the key in an
Authorization: Bearerheader, or inX-Api-Keyif your client cannot set the first one. - Call
whoamion the surface you issued for. It answers with the key's identity, its permissions and, on the client surface, the account behind it. - A
403here means the key is real but belongs to the other surface. Check the address, not the key.
Reference
/api/v1/admin. Issued by staff, scoped by permission, not tied to any one customer.
/api/v1/client. Bound to the account that created it; every query it makes is filtered by that account.
The refusals are distinct on purpose, so a failing integration tells you which of the three checks stopped it.
Retry-After says how long to wait.
Example
KEY=$(cat ~/.config/wisecp.key)
curl -H "Authorization: Bearer $KEY" \
'https://panel.example.com/api/v1/admin/whoami'
# {"data":{"id":7,"type":"admin","name":"Billing sync","permissions":["Invoices/*","Clients/GetClients"]}}
$ch = curl_init('https://panel.example.com/api/v1/admin/whoami');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('WISECP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$permissions = $body['data']['permissions'] ?? [];
Pitfalls
Only a hash is kept, so there is no screen that reveals it later and no support request that can retrieve it. If it is lost, regenerate the credential and update whatever was using it. Treat a regeneration as a small outage and plan it.
The budget is a fixed one-minute window: 120 requests for an admin key and 60 for a client key unless the installation says otherwise. A caller that keeps hammering far past its budget is locked out for a while rather than merely refused. Read X-RateLimit-Remaining and pause on Retry-After.
Failed authentication is counted per address, and enough failures in a short window earn a temporary block with a too_many_auth_failures answer. A retry loop around a wrong key will find this before you do, so fail loudly on 401 instead of retrying.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.