Member API Keys
Scoped reads and opt-in agent operations using Better Auth credentials.
This source implementation requires the matching Auth migration and release before deployment. It adds customer API keys for scoped reads and opt-in agent operations. Agent/run inspection and repository discovery use these same credentials; see Inspect Agents and Runs. Start and Control Agents documents opt-in writes. Membership writes, service accounts and remote MCP login remain separate work.
Issue a key
After lobby login and lobby auth status, choose the explicit account and
numeric GitHub repository IDs:
lobby api-keys create --name monitoring --account ACCOUNT_ID --repository 123456789 --output ./lobby-api.key
lobby api-keys list --limit 20 --offset 0
lobby api-keys inspect --input ./lobby-api.key
lobby api-keys revoke KEY_ID
Create refuses an existing file or symlink and writes the secret once with mode
0600. Output contains metadata and the file path. Keep the file outside Git,
MCP configuration and prompts. Inspect uses the key alone, with no login cookie.
All four commands run outside Lobby agents.
--repository ID,ID selects up to 100 repositories. --ttl SECONDS sets expiry
from one hour to 90 days; default 30 days. Keys default to read-only. Add
--scopes account:read,workspace:read,agent:write explicitly for agent operations;
existing keys never gain that scope automatically. Management accepts --site and
--auth-url, matching login; inspection accepts --site.
List returns keys, total, limit and offset. Limit is 1–100 (default 20).
Advance offset until it reaches total. Concurrent changes can move items between
pages; listing is not a snapshot. Deleted keys disappear.
Keys belong to one person and account; only that person can list or revoke them.
Account/repository/operation scope is immutable: revoke and replace. Repository scope
limits use; creation does not grant or validate GitHub permission. Creation is
not idempotent. After a lost response, list and revoke the unused key before
retrying; the CLI does not replay writes. A lost secret cannot be recovered.
lobby logout removes the local session and does not revoke API keys.
Bearer reads
Send Authorization: Bearer LOBBY_API_KEY over HTTPS:
| Endpoint | Response |
|---|---|
GET /api/v1/me |
user, current account and role, key metadata, observedAt |
GET /api/v1/agents/CONVERSATION_ID/status |
Agent/compute observation matching Workspace Status |
Read a key from a private file instead of putting its value in command arguments:
import json
from pathlib import Path
from urllib.request import Request, urlopen
key = Path("lobby-api.key").read_text().strip()
request = Request("https://lobby.abloatai.com/api/v1/me",
headers={"Authorization": "Bearer " + key})
with urlopen(request, timeout=10) as response:
print(json.load(response))
Key metadata contains id, name, prefix, enabled, createdAt, expiresAt,
accountId, repositoryIds and scopes account:read / workspace:read, plus
optional agent:write. Only
creation returns the secret. observedAt is not an atomic account/VM snapshot.
Every request verifies the key and current ACTIVE membership at Auth, including
verified email and bans. Removed/suspended membership, revocation and expiry
deny subsequent checks; current role changes appear in /me. No session outage
cache is used. Requests already authorized may finish.
Status also checks account, private-conversation ownership and personal GitHub access. Every attached repository must be in key scope. Discovery workspaces without explicit repositories are denied. Reads do not wake a VM, contact the runner or return runner credentials. Cookies and runner capabilities do not authenticate these endpoints.
Request conventions
Valid key verification permits 60 requests per minute, shared by /me, status
and direct Auth identity calls; database quota consumption is atomic. Lobby 429
responses include Retry-After: 60. Unknown-key traffic has no per-key quota;
ingress limits remain an operational requirement.
Lobby errors use {"error":{"code":"unauthorized","requestId":"UUID"}}
and X-Request-ID. Codes include unauthorized (401), not_found (404, including
inaccessible account/conversation/repository), rate_limited (429), and
auth_unavailable / unavailable (503). Verification fails closed; the plugin
can report an unavailable key store as 401. Do not retry a key denial using a
cookie. /me and status have no pagination or mutation/idempotency key;
agent/run and repository collections use opaque cursors.
The CLI manages keys at Auth: GET/POST /api/lobby/keys and
DELETE /api/lobby/keys/KEY_ID. A Better Auth session is required; mutations also
require a trusted product Origin. POST accepts only name, accountId,
repositoryIds, optional expiresIn seconds and optional ordered scopes
(read pair or read pair plus agent:write; 4096-byte maximum). It returns
201 with {key: METADATA, secret: ONE_TIME_VALUE}; DELETE returns 204. Management
errors are {error:{code}}: input 400, session 401, Origin/account denial 403,
missing/foreign key 404, service failure 503. Raw /api/auth/api-key/* HTTP
management is blocked.