Authentication
Bearer tokens, scoped per integration. Versioning is explicit, rate limits are generous, errors are machine-readable.
Bearer tokens
Every request must include an Authorization header carrying a Lectern API token. Tokens look like sk_live_lectern_followed by a 32-character identifier - the prefix tells you whether it’s a live (sk_live_) or test (sk_test_) token.
Authorization: Bearer sk_live_lectern_8aJ4F2pYxQRk0ZqMnVbT9HwLcXKpScopes
Tokens are scoped at creation time. A scope is a verb plus a resource: read:learners, write:finance, read:audit. The least-privilege principle applies - mint a token with only the scopes the integration needs.
read:<resource>- list and read single recordswrite:<resource>- create, update, archivedelete:<resource>- permanent deletion (rare; most resources soft-archive)admin:tenant- settings, integrations, permissions
If a token attempts an operation outside its scopes, the API returns 403 forbidden with an insufficient_scope error code.
Rotation & revocation
Rotate tokens on a regular cadence - quarterly is a sensible default, monthly for production systems. To rotate without downtime: mint a new token with the same scopes, deploy it, then revoke the old one in Settings → API.
Revoked tokens are rejected immediately. Rotation events are written to the audit log with the token’s identifier (never the secret).
Versioning
The API is versioned by date. Send Lectern-Version: 2026-01-01on every request to pin the schema. If you don’t pass a version, Lectern uses the version your tenant was created under - safe by default, but we recommend pinning explicitly.
Breaking changes get a new version. Additive changes (new fields, new endpoints) ship continuously. The changelog documents every version.
Rate limits
Default limits per token: 200 requests per minute for reads, 60 per minute for writes. Bulk endpoints have their own ceiling - see Data import & export.
Every response includes rate-limit headers so clients can self-pace:
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 187
X-RateLimit-Reset: 2026-05-07T13:24:00ZHitting the limit returns 429 Too Many Requests. The Retry-After header tells you how long to wait. If you need a higher limit for an integration, write to dev@lectern.school.
Errors
Errors return a stable JSON envelope with a machine-readable code and a human-readable message. Always switch on code, not the message.
{
"error": {
"code": "invalid_token",
"message": "The API token provided was not recognized.",
"request_id": "req_2pYxQRk0ZqMnVbT"
}
}Common error codes:
invalid_token- token missing, malformed, or revokedinsufficient_scope- token lacks the required scope for the operationnot_found- the resource does not exist or your tenant cannot see itvalidation_failed- payload failed schema validation; details inerror.details[]rate_limited- you’re over your limit; waitRetry-Aftersecondsinternal_error- we broke something; quote therequest_idwhen reporting