Health and Key Check
The two endpoints saying the API is up and what your key can do.
Overview
These two endpoints answer an integration's first two questions: is the API up and what can this key do.
The health check wants no credentials and can be called straight from a monitor or a version check. The key check wants a key while wanting no scope: every valid key may read its own permissions.
Together they make a diagnostic pair. When the health check passes and the key check fails, the trouble is with the credentials rather than the server.
Reference
The Health Check
Returns that the API is up, along with the server time.
curl 'https://panel.example.com/api/v1/admin/ping'const res = await fetch('https://panel.example.com/api/v1/admin/ping');
const { data } = await res.json();
const drift = Math.abs(Date.parse(data.time) - Date.now());$ch = curl_init('https://panel.example.com/api/v1/admin/ping');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// This endpoint WANTS NO KEY: reaching it says nothing about whether your key works.
$up = Api::System()->Ping()['data']['pong'] ?? false;What the Key Is
Returns which key you are using and what it may do.
curl 'https://panel.example.com/api/v1/admin/whoami' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/whoami', {
headers: { Authorization: `Bearer ${apiKey}` },
});
if (res.status === 401) return promptForKey();
const { data } = await res.json();
const canReadInvoices = data.permissions.some((s) => s.startsWith('Invoices/'));$ch = curl_init('https://panel.example.com/api/v1/admin/whoami');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Reading the scopes UP FRONT beats learning them from a 403 on every call.
$me = Api::System()->Whoami()['data'];
$may = fn (string $s) => in_array($s, $me['permissions'], true)
|| in_array(explode('/', $s)[0] . '/*', $me['permissions'], true);Pitfalls
The health endpoint checks no credentials: it answers successfully even with a key revoked, expired or never sent. Resting a connection test on it alone reports a healthy system while the real calls fail.
The time returned sits in the server's own zone and can differ from yours. The dates on the other endpoints share that zone, so comparing one against your own clock gives results that do not line up. Take this endpoint's time as the reference.
The permission list can hold a group wildcard or a star covering everything rather than the actions one by one. Looking for an action with a plain comparison gives a false negative on a key that carries a wildcard. Test the group wildcard as well.
When a call answers 403 the cause is either a missing scope or the wrong key. The key endpoint tells the two apart in one call: with it working the key is valid and the trouble lies in the scope. A restricted address and a passed request limit show here as well.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.