Projects & API Keys
Create and list projects within an org, and manage the API keys used to authenticate against them.
Projects
GET /api/orgs/:orgSlug/projects
List all projects in an org.
Auth: session cookie
Response 200
{
"projects": [
{ "id": "proj_01abc", "org_id": "org_01xyz", "name": "Default", "slug": "default", "created_at": 1720392000000 }
]
}
Ordered by created_at ascending. No pagination.
Errors:
404—{ "error": "Organization not found" }403—{ "error": "Not a member" }— authenticated user isn’t a member of this org
POST /api/orgs/:orgSlug/projects
Create a project in an org.
Auth: session cookie · requires admin or owner role
Request body
| field | type | required | description |
|---|---|---|---|
| name | string | yes | Project name. Its slug is derived automatically (slugify(name)) — not settable directly |
Response 201
{ "id": "proj_01new", "name": "Payments", "slug": "payments" }
Errors:
404—{ "error": "Organization not found" }403—{ "error": "Insufficient permissions" }— thememberrole cannot create projects400—{ "error": "Name is required" }402—{ "error": "usage_limit_exceeded", "message": "Project limit reached. Upgrade your plan." }— org is at its plan’s project cap. This check is best-effort: a billing-DB error is swallowed and does not block creation
Common responses (401) apply — see Authentication. 429 doesn’t apply to this endpoint.
API keys
Keys are project-scoped (created against whichever project the request resolves to) and returned in full exactly once, at creation. GET/POST/DELETE below are mounted at both the plain path and /api/orgs/:orgSlug/projects/:projectSlug/settings/api-keys — use the org-scoped path. At the plain path, GET /api/settings/api-keys always returns 403 (its admin-role check depends on org context that only the org-scoped mount resolves), and POST/DELETE there only work correctly when authenticated with a project API key rather than a session cookie (a session cookie at the plain path doesn’t resolve an org/project, and a key created that way ends up with an empty org_id/project_id).
GET /api/orgs/:orgSlug/projects/:projectSlug/settings/api-keys
List API keys for the resolved project.
Auth: session cookie · requires admin or owner role
Response 200
{
"keys": [
{ "id": "key_01abc", "name": "CI", "key_prefix": "lm_ak_3f9a2b1c...", "last_used_at": 1720392000000, "created_at": 1720000000000 }
]
}
The key material itself (hash) is never returned; key_prefix is the first 12 characters of the raw key plus ..., for identifying a key in a list. last_used_at is null until the key is first used.
POST /api/orgs/:orgSlug/projects/:projectSlug/settings/api-keys
Create an API key for the resolved project.
Auth: session cookie (no role restriction beyond being a member — any role can create a key)
Request body
| field | type | required | description |
|---|---|---|---|
| name | string | yes | Label for the key |
Response 201
{ "id": "key_01new", "key": "lm_ak_3f9a2b1c8d7e6f5a4b3c2d1e0f9a8b7c", "name": "CI" }
key is the plaintext key — it is generated with a lm_ak_ prefix, only ever returned in this response, and cannot be retrieved again (only its key_prefix shows up in GET).
Errors: 400 — { "error": "Name is required" }
DELETE /api/orgs/:orgSlug/projects/:projectSlug/settings/api-keys/:id
Revoke an API key.
Auth: session cookie (no role restriction beyond being a member)
Response 200
{ "ok": true }
Errors: 404 — { "error": "Not found" } — no key with that ID in this project
Common responses (401; 402 and 429 don’t apply) — see Authentication.