lema · docs · api
Keys, usage & identity
The account surface. Key lifecycle is session-only by design — a lema_live_ key can never mint, list, or revoke keys, so a leak never outruns revocation. The two reads — /usage and /me — work with any authenticated key.
POST
/api-keys
/api-keysMint a key
Mints a lema_live_ key bound to one org. Session-only by design: an API key calling this gets a 403 — a leaked key must never be able to mint its own successors, or revocation means nothing. The full key string is returned exactly once, here, and never again.
Request body
org_idstring (UUID)required- The org the key is bound to.
namestring- A label for the key (max 100 characters).
scopesstring[]- decisions:read and/or decisions:write. Omitted → read-only. A scope above your role in the org is refused.
expires_in_daysinteger- 0 (never — the default) to 366.
Response
keystring- The full lema_live_ key — shown exactly once, never retrievable again.
idstring (UUID)- The key id, for revocation.
org_idstring (UUID)- The org it answers over.
namestring- Your label.
lookup / last4string- The masked identifiers the list endpoint shows.
scopesstring[]- What the key can do.
created_atstring (RFC3339)- When it was minted.
expires_at / last_used_at / revoked_atstring (RFC3339) · optional- Lifecycle timestamps, present once they apply.
Errors
400missing org_id, over-long name, unknown scope, or expires_in_days outside 0–366.403called with an API key, or the requested scopes exceed your role in the org.404the org does not exist — or is not yours; the two read the same.409you have no workspace in this org yet — connect a repo first, or the key would answer over nothing.501API keys are not configured on this deployment.
Success is 201 Created.
The practical path is the UI at lema.sh/account/api-keys — same contract, same one-time reveal.
$ curl https://api.lema.sh/api-keys \
-H "Authorization: Bearer <session JWT — not an API key>" \
-H "Content-Type: application/json" \
-d '{"org_id": "<org uuid>", "name": "ci-reader",
"scopes": ["decisions:read"], "expires_in_days": 90}'{
"id": "<key uuid>",
"org_id": "<org uuid>",
"name": "ci-reader",
"lookup": "<masked>",
"last4": "<masked>",
"scopes": ["decisions:read"],
"created_at": "<RFC3339>",
"expires_at": "<RFC3339>",
"key": "lema_live_<shown exactly once>"
}GET
/api-keys
/api-keysList keys
Your keys, masked: name, lookup fragment, last4, scopes, and lifecycle timestamps. The full key string is never listable — if you lost it, revoke and re-mint.
No request body.
Response
keysobject[]- Masked key records — the mint response minus the key field.
Errors
403called with an API key.501API keys are not configured on this deployment.
$ curl https://api.lema.sh/api-keys \
-H "Authorization: Bearer <session JWT>"{
"keys": [
{
"id": "<key uuid>",
"org_id": "<org uuid>",
"name": "ci-reader",
"lookup": "<masked>",
"last4": "<masked>",
"scopes": ["decisions:read"],
"created_at": "<RFC3339>",
"last_used_at": "<RFC3339>"
}
]
}DELETE
/api-keys/{keyID}
/api-keys/{keyID}Revoke a key
Soft-revokes one key by id. A revoked key stops verifying immediately; the record stays listed with its revoked_at set.
Parameters
keyIDpath (UUID)required- The key id from mint or list.
Errors
400keyID is not a UUID.403called with an API key.404no such key — or not yours; the two read the same.501API keys are not configured on this deployment.
Success is 204 No Content — an empty body.
$ curl -X DELETE https://api.lema.sh/api-keys/<key uuid> \
-H "Authorization: Bearer <session JWT>"204 No Content
GET
/usage
/usageWhere you stand
Your plan and the live meters: the unified MCP-query wallet (asks + retrieves, with the breakdown), imports, captures, and when everything resets. This endpoint never charges the wallet — it IS the meter.
No request body.
Response
planstring- free or pro.
mcp_queriesobject- { used, limit } — the summed daily wallet. limit is JSON null when unlimited.
breakdownobject- { asks, retrieves } — how the wallet was spent.
importsobject- { used, limit } — daily imports.
capturesobject- { used, limit } — daily decision captures.
resets_atstring (RFC3339)- Next UTC midnight — when every daily meter resets.
$ curl https://api.lema.sh/usage \
-H "Authorization: Bearer $LEMA_API_TOKEN"{
"plan": "pro",
"mcp_queries": { "used": …, "limit": 2500 },
"breakdown": { "asks": …, "retrieves": … },
"imports": { "used": …, "limit": 50 },
"captures": { "used": …, "limit": 500 },
"resets_at": "<RFC3339 — next UTC midnight>"
}GET
/me
/meWho the key is
Echoes the verified principal: the user and org the credential resolves to, its scopes, and the org member count. Useful as the first call in any integration — it proves the key works before you build on it.
No request body.
Response
user_idstring (UUID)- The user the credential belongs to.
org_idstring (UUID)- The org it operates in.
emailstring- The account email.
scopesstring[]- What this credential may do.
org_rolestring- Advisory only — every write is enforced server-side regardless of what this says.
org_member_countinteger- How many people are in the org.
$ curl https://api.lema.sh/me \
-H "Authorization: Bearer $LEMA_API_TOKEN"{
"user_id": "<uuid>",
"org_id": "<uuid>",
"email": "[email protected]",
"scopes": ["decisions:read"],
"org_role": "member",
"org_member_count": 1
}