Skip to content

API Keys ​

API keys are how external automation tools authenticate to Kinderpedia. Each key is bound to one school and grants access to the v1 surface.

Creating a key ​

Open Developer (sidebar) → API Keys tab → Create key.

Fields:

  • Name — a human label like "Make.com lead sync" or "Nightly report". Required.
  • Description (optional) — extra notes.
  • Expires at (optional) — pick a date or "Never". For long-lived integrations, leave Never; for short test keys, set a 7-day expiry.

Click Create. The key is shown once in a modal:

kpa_live_4F8a9bC2dE3fG4hI5jK6lM7nO8pQ9rStUvWxYz01_2024

Copy it immediately. The modal also shows the prefix (kpa_live_4F8a9bC2) which is what's displayed in the keys list afterwards — the full key is never recoverable.

Storage model ​

Keys are stored as SHA-256 hashes of the raw key — never plaintext. The api_keys table has:

ColumnUse
hashSHA-256 of the raw key. Used for auth lookup.
prefixFirst 8 chars after kpa_live_ (for display + audit)
nameYour label
descriptionNotes
expires_atOptional auto-expiry
revoked_atSet when manually revoked
last_used_atUpdated on every successful auth
created_at / created_byAudit

If our DB is leaked, the raw keys are still safe — only the hashes are stored.

Using a key ​

bash
curl -H "Authorization: Bearer kpa_live_…" \
  https://your-kinderpedia.com/api/v1/whoami

The server SHA-256s the bearer value and looks up the row. If found, validated (not revoked, not expired), and the school is active, the request proceeds.

A kpa_live_ prefix is required — keys without it are rejected before lookup. This keeps an attacker from brute-forcing hash collisions against arbitrary bearer values.

Revoking a key ​

In Developer → API Keys, click the Revoke icon on a row. Confirm in the modal.

Revocation sets revoked_at = NOW(). From that point onward, requests with that key return 401 immediately. Revocation is irreversible — to re-enable access, create a new key.

Revocation fires an audit log: api_key_revoked with the key prefix + who did it.

Rotating ​

There's no in-place rotation. To rotate:

  1. Create a new key (note the raw value).
  2. Update your integration's credentials to use the new key.
  3. Verify the integration works.
  4. Revoke the old key.

Both old and new keys work simultaneously while you transition. Plan ~5 min overlap to be safe.

Expiry ​

If you set expires_at, the key auto-invalidates at that timestamp (server-side check; no manual revoke needed). Past expires_at, requests return 401 with error: "key_expired".

For Make.com / n8n integrations that should never expire, leave the field blank. For test scripts or one-off runs, set a short expiry — easier than remembering to revoke.

Last-used timestamp ​

Every successful auth updates last_used_at. The keys list shows it as "Last used 3 hours ago" — useful for spotting dormant keys you should revoke.

Keys never used at all show "Never used" — common after creation but before the integration is connected.

Per-school scoping ​

Each key is bound to one school. The bound school is determined at creation time (from the user's current school context). Switching schools in the SPA doesn't change existing keys.

If your organisation has multiple schools, each one needs its own key.

What happens on auth ​

When a request hits ^/api/v1/:

  1. The API key authenticator reads the Authorization header.
  2. Validates Bearer kpa_live_… format.
  3. SHA-256s the value and looks up the matching key record.
  4. Verifies the key is not revoked and not past its expiry.
  5. Loads the school and confirms its subscription includes the Leads Management module.
  6. Mints a synthetic user carrying the school id + the key's scopes.
  7. Updates last_used_at (async, fire-and-forget).
  8. Request proceeds.

The synthetic ApiKeyUser implements getKindergartenId(), which means our existing KindergartenScopeExtension auto-filters every query by the right school. The same filtering logic that protects SPA users protects API key users.

Common errors ​

CodeBodyLikely cause
401{ "error": "missing_bearer" }No Authorization header.
401{ "error": "invalid_key" }Header present, but key doesn't match any row.
401{ "error": "key_revoked" }Key was revoked.
401{ "error": "key_expired" }Past expires_at.
403{ "error": "module_not_subscribed" }School lost leadsmanagement subscription.

Best practices ​

  • One key per integration. Don't share keys between Make.com + n8n + custom scripts.
  • Name keys descriptively. "Make.com lead-to-Slack" is better than "key 1".
  • Set expiry on test keys. Production keys are usually never-expire.
  • Rotate every 6-12 months for production. Even without a leak, fresh keys reduce blast radius.
  • Revoke immediately on employee departure or any suspected compromise.

Kinderpedia Admissions Help Center