Developer API
The Developer API is Kinderpedia's HTTP interface for external automation tools — Make.com, n8n, Zapier, your bespoke scripts. It lets you read leads, create notes, complete activities, register stage transitions, and subscribe to outbound webhooks. All authenticated via API keys you control.
Different from the in-app JWT-cookie API used by the SPA itself (which is browser-only). The Developer API is designed for server-to-server.
What you can do
- Read your roster: leads, notes, activities, pipelines, stages, applicant statuses, forms
- Write: create + update leads, create notes, complete activities, transition stages, archive/unarchive
- Subscribe to events: outbound webhooks fire when things happen (lead created, stage moved, note added, etc.)
- Idempotently retry: every POST/PUT accepts an
Idempotency-Keyheader; duplicates replay the same response for 24h
What you cannot do
- Use the Developer API as a frontend — there's no XHR-compatible session, no CSRF flow
- Access another school's data — keys are tightly scoped to one school
- Bypass rate limits — 60 requests/minute per key, hard 429s outside that window
- Trigger writes outside the v1 surface — only the documented endpoints are exposed (we don't proxy the SPA API)
API key model
Keys look like GitHub PATs: kpa_live_<random>. Stored as SHA-256 hash on the server, never plaintext. The raw key is shown once at creation — copy it then or rotate.
See API keys for the full lifecycle (creation, rotation, revocation, expiry).
Auth header
Every request:
Authorization: Bearer kpa_live_…
Content-Type: application/jsonThe bearer token resolves to a per-school identity. There's no separate X-KINDERGARTEN-ID header (unlike the SPA API) — the key already binds you.
Endpoint structure
All endpoints live under /api/v1/:
GET /api/v1/whoami
GET /api/v1/leads
GET /api/v1/leads/{id}
POST /api/v1/leads
PUT /api/v1/leads/{id}
POST /api/v1/leads/{id}/archive
POST /api/v1/leads/{id}/unarchive
POST /api/v1/leads/{id}/transition
GET /api/v1/leads/{id}/notes
POST /api/v1/leads/{id}/notes
GET /api/v1/leads/{id}/activities
POST /api/v1/leads/{id}/activities
POST /api/v1/leads/{id}/activities/{aid}/complete
GET /api/v1/pipelines
GET /api/v1/stages
GET /api/v1/applicant-statuses
GET /api/v1/formsPlus the no-auth meta endpoint:
GET /api/v1/openapi.jsonFor complete schemas + request/response shapes, see OpenAPI reference.
Versioning
The /v1 prefix is the current and only version. Breaking changes will move to /v2 (when applicable); v1 will stay supported for at least 12 months after v2 ships.
Backward-compatible additions (new endpoints, new optional fields) happen on v1 without notice — your existing integrations keep working.
Cursor pagination
List endpoints use opaque cursor pagination:
GET /api/v1/leads?after=eyJpZCI6MTIzfQ&limit=50Response includes a Link header for the next page:
Link: <https://.../api/v1/leads?after=eyJpZCI6MTczfQ&limit=50>; rel="next"When the response has no Link header (or no next rel), you've reached the end. Don't try to compute total counts or offset — pagination is forward-only.
Field names
The public API uses simplified field names, not the raw DB column names:
| Public | DB column |
|---|---|
email | student_email |
phone | student_phone |
is_applicant | derived from roster_type === 'applicant' |
parent_email | from linked parents.email |
Most of the mapping is in LeadV1Controller::PUBLIC_TO_COLUMN. The OpenAPI document is the canonical reference.
Errors
Errors return JSON:
{
"error": "validation_failed",
"message": "Field 'parent_email' must be a valid email address.",
"details": {
"field": "parent_email"
}
}HTTP status codes:
| Code | Meaning |
|---|---|
| 200 | OK |
| 201 | Created |
| 400 | Validation error / bad input |
| 401 | Invalid / missing API key |
| 403 | Key valid but missing required scope |
| 404 | Resource not found (or not in your school) |
| 409 | Conflict (idempotency replay with different body) |
| 422 | Business rule violation (e.g. stage transition not allowed) |
| 429 | Rate limit exceeded |
| 5xx | Server error — safe to retry |
Scopes (planned)
Keys currently have a single scope: full access to v1. Future versions will introduce granular scopes (leads:read, leads:write, notes:write) — for now, treat every key as having full v1 access.
Pages in this section
- API keys — creation, rotation, revocation
- Authentication — header format, identity resolution
- Limits and idempotency — rate limits, idempotency keys
- Webhooks — outbound event subscriptions
- Dead-letter UI — failed delivery management
- OpenAPI reference — full schema + Make.com / n8n setup
Quick example
bash
# Whoami — confirm key works
curl -H "Authorization: Bearer kpa_live_xxx" \
https://your-kinderpedia.com/api/v1/whoami
# List leads
curl -H "Authorization: Bearer kpa_live_xxx" \
"https://your-kinderpedia.com/api/v1/leads?limit=10"
# Create a lead
curl -X POST \
-H "Authorization: Bearer kpa_live_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-unique-key-001" \
-d '{"student_name":"Anna Smith","parent_email":"[email protected]","form_id":1}' \
https://your-kinderpedia.com/api/v1/leads