Hawkings uses two pieces of identity on every authenticated request:
- An API key —
hk-{...}, 5 segments. Identifies the user.
- A learning platform — picked per request by
code (slug) or uuid.
Identifies which workspace the call operates on.
A single API key gives access to every platform the user belongs to.
You pick which one to act on by passing platformCode (preferred) or
platform (the 24-char UUID) — the SDK turns them into headers.
code is the human-readable slug. Use it when you have it
("acme-academy", "unimiami"). Fall back to uuid for older platforms
where code is still null.
Pass the key to the SDK
The SDK reads HAWKINGS_API_KEY and HAWKINGS_PLATFORM_CODE (or
HAWKINGS_PLATFORM for the UUID form) from the environment by default.
You can also pass them in code:
import Hawkings from "@hawkings/sdk";
// Preferred: identify the platform by code
const hk = new Hawkings({
apiKey: "hk-...-...-...-...-...",
platformCode: "acme-academy",
});
// Or by UUID (universal fallback — always works)
const hk = new Hawkings({
apiKey: "hk-...-...-...-...-...",
platform: "abc123def456ghi789jkl012",
});
require_once 'vendor/autoload.php';
// Preferred: identify the platform by code
$hk = new \Hawkings\Client([
'api_key' => 'hk-...-...-...-...-...',
'platform_code' => 'acme-academy',
]);
// Or by UUID
$hk = new \Hawkings\Client([
'api_key' => 'hk-...-...-...-...-...',
'platform' => 'abc123def456ghi789jkl012',
]);
from hawkings import Hawkings
hk = Hawkings(api_key="hk-...", platform_code="acme-academy")
curl https://api.hawkings.education/v1/courses \
-H "x-api-key: hk-..." \
-H "X-Learning-Platform-Code: acme-academy"
The SDK sends:
| Header | When |
|---|
x-api-key | Always (except on unauthenticated endpoints). |
X-Learning-Platform-Code | When you set platformCode. |
X-Learning-Platform-Uuid | When you set platform. |
If both are set, the backend cross-checks them — they must point to the
same workspace.
The legacy long-form API key (hk-...-{platformUuid}) is no longer
accepted by the SDK. Split it: take the first 5 segments as apiKey and
pass the trailing 24-hex as platform separately.
Scopes
Every key has one or more scopes. The default key issued in the
dashboard carries read:* and write:* for everything in its workspace.
For machine-to-machine integrations create scoped keys:
| Scope | What it allows |
|---|
read:courses | List, retrieve, expand Course, Cohort, Unit, Lesson. |
write:courses | Above + create / update / delete authoring resources. |
read:students | List students and their progress. |
write:submissions | Create submissions (use this for student-facing apps). |
ai:generate | Run *.generate*() calls. |
ai:grade | Run submissions.gradeWithAi(). |
The dashboard generates scoped keys via copy-paste; programmatically
you’d use the Auth API.
End-user authentication
If you’re building a student-facing product, you don’t want to ship
your platform-wide key to a browser. Use the token flow:
// Server-side: ask Hawkings for a one-time token for this user
const { token } = await hk.auth.tokenStart({ email: student.email });
// Send `token` to your client
// Server-side: ask Hawkings for a one-time token for this user
$result = $hk->auth->tokenStart(['email' => $student->email]);
$token = $result->token;
// Send `$token` to your client
// Client-side: exchange the token for a session-scoped key
const session = await hk.auth.tokenFinish(token);
// session.api_key is a short-lived key scoped to this user
// Client-side: exchange the token for a session-scoped key
$session = $hk->auth->tokenFinish($token);
// $session->api_key is a short-lived key scoped to this user
The session key inherits only the scopes the student needs:
read:lessons, write:submissions, ai:tutor. It expires in 24 hours.
Multiple workspaces
A single API key gives access to every platform the user belongs to.
List them and switch by code or uuid:
const platforms = await hk.platforms.list();
// → [{ id: 1, uuid: "...", code: "acme", name: "Acme Academy", ... }, ...]
// Pick by code (preferred)
const acme = hk.withPlatformCode("acme");
const beta = hk.withPlatformCode("beta");
// Or by uuid (when `code` is still null)
const legacy = hk.withPlatform(platforms[0].uuid);
await acme.courses.list();
await beta.courses.list();
$platforms = $hk->platforms->list();
// → [{ id: 1, uuid: "...", code: "acme", name: "Acme Academy", ... }, ...]
$acme = $hk->withPlatformCode('acme');
$beta = $hk->withPlatformCode('beta');
You can also override the platform on a single call without building a
new client — see your SDK’s per-request options.
Rotating a key
Rotating is non-disruptive:
- Issue a new key in the dashboard.
- Deploy it.
- Revoke the old one.
Revoked keys return a 401 authentication_error
on the next request.
Self-hosted instances
If you’re running Hawkings on your own infrastructure, point the SDK at
your base URL:
new Hawkings({
apiKey: "hk-...",
baseURL: "https://api.your-school.example",
});
new \Hawkings\Client([
'api_key' => 'hk-...',
'base_url' => 'https://api.your-school.example',
]);