Authentication
The Developer API uses API key authentication via the Authorization: Bearer … header. There's no OAuth flow, no session cookies, no CSRF token. The key is the credential.
Required header
Authorization: Bearer kpa_live_<your-key>Every request to /api/v1/* must include this header. Requests without it return:
401 Unauthorized
{ "error": "missing_bearer" }Content type
For POST / PUT requests:
Content-Type: application/jsonWe accept application/json only — no application/x-www-form-urlencoded, no multipart/form-data. Body must be valid JSON.
The single exception is the OpenAPI spec endpoint (GET /api/v1/openapi.json) which is no-auth and always returns JSON.
What identity does the key resolve to?
When a key authenticates, Kinderpedia mints a synthetic API key user (class ApiKeyUser) representing:
- The school the key was created for (
getKindergartenId()) - The scopes the key carries (currently always "full v1" — granular scopes are planned)
This synthetic user goes through the same access-control gates as a regular SPA user. Every data query is auto-filtered by the synthetic user's school at the database layer, exactly as it does for SPA users. There's no way for an API key to read or write data outside its bound school.
Whoami
A diagnostic endpoint to confirm your key works:
GET /api/v1/whoamiReturns:
json
{
"kindergarten_id": 12,
"school_name": "Demo International School",
"key_name": "Make.com lead sync",
"key_prefix": "kpa_live_4F8a9bC2",
"scopes": ["v1:full"],
"created_at": "2026-04-01T10:14:22+00:00",
"expires_at": null,
"rate_limit": {
"limit": 60,
"window_seconds": 60
}
}Use this as your first call in any new integration to verify connectivity + scope before making real reads/writes.
What's NOT used
- No
X-KINDERGARTEN-IDheader. The key already binds the school. Including this header is harmless but ignored. - No
X-Requested-With. CSRF-style headers are irrelevant for server-to-server. - No
Cookie: JWToken=…. JWT cookies are for the SPA only. The API key firewall ignores cookies. - No CORS preflight. v1 endpoints are not browser-targeted; if you call them from a browser, you'll hit CORS errors — that's intentional. Don't expose your key in browser code.
Multiple keys, one tool
If your automation platform (Make.com / n8n / Zapier) supports multiple scenarios connecting to Kinderpedia, each scenario should have its own key. Why?
- Revoking one scenario's key doesn't break others.
last_used_atper key shows you which scenarios are active.- Rate limits are per-key — sharing one key splits 60 req/min across all scenarios.
The Make.com/n8n integration is the same as any other client: paste the bearer token into the HTTP module's authorization config.
Server-side only
API keys should NEVER be embedded in:
- Frontend JavaScript / mobile apps
- Public Git repos
- Logs you ship to third parties
- URL query strings (browser history captures them)
If a key leaks, revoke it immediately and create a new one. The audit log will tell you when it was last used.
Rate limiting
60 requests per minute per key, sliding window. See Limits and idempotency for the full mechanics.
When you hit the limit:
429 Too Many Requests
Retry-After: 8
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
{ "error": "rate_limit_exceeded" }Honour Retry-After — that's the seconds until your window resets.
Auth failure modes
| Code | Body error | What to do |
|---|---|---|
| 401 | missing_bearer | Add the header. |
| 401 | invalid_key | Key not found. Check for typos or that you copied the full value. |
| 401 | key_revoked | Key was revoked. Create a new one. |
| 401 | key_expired | Past expires_at. Create a new one. |
| 403 | module_not_subscribed | School lost the admissionscrm subscription. Renew with Kinderpedia. |
| 429 | rate_limit_exceeded | Slow down + honour Retry-After. |
Auth performance
The auth check is a single indexed lookup on api_keys.hash plus a subscriptions join. Should add <5ms to your request. No caching is needed on your side.
TLS
All endpoints are HTTPS-only. Plain HTTP requests are redirected to HTTPS in production. Don't disable TLS verification in your HTTP client — there's no scenario where bypassing TLS is the right call for production.