Authentication
Every /v1/saas/* endpoint except POST /auth/register and
POST /auth/login requires a bearer API key:
curl https://api.lecturia.ai/v1/saas/me \
-H "Authorization: Bearer lk_live_..."Key kinds
| Prefix | Environment | Billing |
|---|---|---|
lk_live_ | Production | Synthesis charges credits |
lk_test_ | Sandbox | Never deducts credits |
Both kinds use the same base URL — the key alone selects the environment. There is no separate sandbox hostname.
What is NOT accepted
- Session JWTs. The tokens returned by
/auth/registerand/auth/loginare account sessions, not API credentials. Presenting one on any other/v1/saas/*route returns403bearer_not_allowed_on_saas. - Query-string keys. The key travels in the
Authorizationheader, never in the URL.
Scopes
Keys carry scopes: read, write, admin. Administrative endpoints (key
minting, webhook management) require admin; a key can only mint keys with
a subset of its own scopes (403
scope_escalation otherwise). Give
day-to-day integrations read+write and keep an admin key aside.
Key lifecycle
- Plaintext is returned exactly once at mint (and on webhook secret rotation, once again). Only a hash is stored server-side — a lost key is a revoke-and-remint, never a recovery.
- Revoke with
DELETE /v1/saas/keys/{id}. Revocation propagates in seconds; the revoked key answers401api_key_revoked. last_used_atinGET /keysmay lag ~60 s (coalesced writes).
Consent to updated terms
When Lecturia publishes new terms or a new privacy policy, every call made
with a key of an account that has not accepted them answers 403
consent_required:
{
"error": {
"code": "consent_required",
"message": "the account owner must sign in to the Lecturia app and accept the updated terms",
"details": {
"owed": ["terms"],
"terms_version": "2026-09-01",
"privacy_version": "2026-09-01"
},
"request_id": "01J9Z8REQ9"
}
}details.owed names the documents still to accept (terms, privacy or
both), and terms_version and privacy_version are the current versions.
The error applies to every key of the account, live and sandbox alike.
To resolve it, the account owner signs in to app.lecturia.ai and accepts the updated documents. The API has no endpoint for this. Once accepted, the same keys work again: nothing needs to be minted or rotated. Treat the error as not retryable until the owner has accepted.
Two calls always work, so a leaked credential can be shut off without accepting first:
DELETE /v1/saas/keys/{id}revokes a key.DELETE /v1/saas/webhooks/{id}deletes a webhook endpoint.
POST /auth/register and POST /auth/login do not take a key and are never
refused for consent.
Rate limits and errors
Auth endpoints are velocity-limited (429
rate_limited — back off and retry). Every
error is the uniform envelope described in Error codes.