Download OpenAPI specification:
REST API for the merged agentops-server process — composes routes from
agentops-api, docbrain-api (nested under /docbrain), and
agentops-heavy-api (accounts/auth, team management, repository
connection/indexing, search, and webhooks) onto one Axum router, one
port.
Three auth models coexist depending on the route group:
sessionAuth): a Bearer token from POST /auth/login
or POST /auth/signup, used by the web UI and anything acting as a
specific user.apiKeyAuth): a Bearer token from agentops api-key generate / POST /auth/api-keys, used by CLI/MCP/service callers./webhooks/* routes verify an
HMAC signature header instead — see each route's description.Most /repos/* and /search/* routes accept either a session or an
API key (sessionOrApiKey); the tenant resolves from the session if
present, else from a tenant/org request field.
Unauthenticated (there's no session yet on a brand-new instance), but
deliberately first-run only: 403s once any account already exists,
so an anonymous caller can't rewrite a running instance's secrets.
Writes .env in the server process's working directory; the caller
must restart the process for it to take effect (no hot-reload).
| secrets_master_key required | string 64 hex chars (32 bytes) — generate with |
| database_url | string postgres:// connection string for the code-graph store; omit for SQLite. |
| addr | string |
| access_mode | string Enum: "advisor" "full" |
| signup_mode | string Enum: "open" "first-user-only" |
| anthropic_api_key | string |
| linear_api_key | string |
| github_app_id | string |
| github_app_private_key | string |
| github_webhook_secret | string |
| qdrant_url | string |
{- "secrets_master_key": "string",
- "database_url": "string",
- "addr": "0.0.0.0:8420",
- "access_mode": "advisor",
- "signup_mode": "open",
- "anthropic_api_key": "string",
- "linear_api_key": "string",
- "github_app_id": "string",
- "github_app_private_key": "string",
- "github_webhook_secret": "string",
- "qdrant_url": "string"
}{- "ok": true
}Always mints a brand-new tenant for the new user. Once
AGENTOPS_SIGNUP_MODE=first-user-only (the default for self-host
deployments) and any account already exists, this requires a valid
invite_token — see POST /invites/accept for how an invited user
actually joins the inviting org afterward (signup alone never
redeems the invite).
| email required | string <email> |
| password required | string |
| first_name required | string |
| last_name required | string |
| invite_token | string Proves this signup is invite-driven; required once AGENTOPS_SIGNUP_MODE=first-user-only and an account already exists. Does not itself join the inviting org — see POST /invites/accept. |
{- "email": "user@example.com",
- "password": "string",
- "first_name": "string",
- "last_name": "string",
- "invite_token": "string"
}{- "user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "tenant": "string",
- "avatar_url": "string",
- "handle": "string",
- "bio": "string",
- "location": "string",
- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string",
- "two_factor_enabled": true,
- "onboarding_completed": true
}, - "session_token": "string"
}If the account has 2FA enabled, returns a 202 challenge instead of a session — complete it via POST /auth/login/2fa.
| email required | string <email> |
| password required | string |
{- "email": "user@example.com",
- "password": "string"
}{- "user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "tenant": "string",
- "avatar_url": "string",
- "handle": "string",
- "bio": "string",
- "location": "string",
- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string",
- "two_factor_enabled": true,
- "onboarding_completed": true
}, - "session_token": "string"
}| challenge_token required | string |
| code required | string |
{- "challenge_token": "string",
- "code": "string"
}{- "user": {
- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "tenant": "string",
- "avatar_url": "string",
- "handle": "string",
- "bio": "string",
- "location": "string",
- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string",
- "two_factor_enabled": true,
- "onboarding_completed": true
}, - "session_token": "string"
}{- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "tenant": "string",
- "avatar_url": "string",
- "handle": "string",
- "bio": "string",
- "location": "string",
- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string",
- "two_factor_enabled": true,
- "onboarding_completed": true
}Every field optional — omitted means "leave unchanged".
| first_name | string |
| last_name | string |
| handle | string |
| bio | string |
| location | string |
{- "first_name": "string",
- "last_name": "string",
- "handle": "string",
- "bio": "string",
- "location": "string"
}{- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "tenant": "string",
- "avatar_url": "string",
- "handle": "string",
- "bio": "string",
- "location": "string",
- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string",
- "two_factor_enabled": true,
- "onboarding_completed": true
}| theme_pref | string |
| default_search_scope | string |
| show_gotcha_callouts | boolean |
| graph_layout_algorithm | string |
{- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string"
}{- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "tenant": "string",
- "avatar_url": "string",
- "handle": "string",
- "bio": "string",
- "location": "string",
- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string",
- "two_factor_enabled": true,
- "onboarding_completed": true
}Revokes every other session on success — the request that proved it knows the new password doesn't lock itself out.
| current_password required | string |
| new_password required | string |
{- "current_password": "string",
- "new_password": "string"
}{- "updated": true
}Idempotent — safe to call more than once (e.g. re-clicking "Continue to dashboard").
{- "id": 0,
- "email": "string",
- "first_name": "string",
- "last_name": "string",
- "tenant": "string",
- "avatar_url": "string",
- "handle": "string",
- "bio": "string",
- "location": "string",
- "theme_pref": "string",
- "default_search_scope": "string",
- "show_gotcha_callouts": true,
- "graph_layout_algorithm": "string",
- "two_factor_enabled": true,
- "onboarding_completed": true
}The raw key is returned exactly once, in this response — only its prefix is ever visible again.
| name required | string |
{- "name": "string"
}{- "id": 0,
- "name": "string",
- "key_prefix": "string",
- "last_used_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "key": "string"
}Owner-only — used by the /welcome onboarding checklist's workspace-setup item.
| name required | string |
{- "name": "string"
}{- "name": "string"
}Demoting/removing another active admin requires being the Owner; the org can never end up with zero active admins.
| user_id required | integer |
| role | string |
| status | string |
{- "role": "string",
- "status": "string"
}| label required | string |
| cloned_from required | string |
| capabilities required | Array of strings |
{- "label": "string",
- "cloned_from": "string",
- "capabilities": [
- "string"
]
}Deletes every repo connection, credential, docbrain data, and team row for the tenant except the audit log.
| confirm_tenant required | string Must exactly match the caller's own tenant — type-to-confirm safety check. |
{- "confirm_tenant": "string"
}No email is sent — the response includes the raw token so the caller can build a copyable /invite/{token} link.
| email required | string <email> |
| role required | string |
| note | string |
{- "email": "user@example.com",
- "role": "string",
- "note": "string"
}{- "id": 0,
- "email": "string",
- "role": "string",
- "note": "string",
- "status": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "expires_at": "2019-08-24T14:15:22Z",
- "token": "string"
}Only member/viewer rows are override-editable; a diff for an admin or billing row is silently ignored.
required | Array of objects |
{- "changes": [
- {
- "user_id": 0,
- "repo_id": "string",
- "allowed": true
}
]
}| token required | string |
{- "token": "string"
}{- "tenant": "string",
- "role": "string"
}| provider required | string |
| auth_type required | string |
| secret required | string |
| refresh_token | string |
| expires_at | string <date-time> |
{- "auth_type": "string",
- "secret": "string",
- "refresh_token": "string",
- "expires_at": "2019-08-24T14:15:22Z"
}{- "provider": "string",
- "auth_type": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Generates a keypair and returns the public half — add it as a read-only Deploy Key on the repo, then verify.
| tenant | string Required on the API-key path; ignored on the session path (derived from the session). |
| repo_id required | string |
| repo_url required | string |
{- "tenant": "string",
- "repo_id": "string",
- "repo_url": "string"
}{- "connection": {
- "id": "string",
- "tenant": "string",
- "repo_url": "string",
- "method": "ssh",
- "public_key_openssh": "string",
- "status": "string",
- "created_at": "2019-08-24T14:15:22Z"
}, - "instructions": "string"
}Requires Qdrant to be configured (AGENTOPS_QDRANT_URL) — 503s otherwise.
| path required | string |
{- "path": "string"
}{- "indexed": 0
}| path required | string |
| q required | string |
| top_k | integer Default: 5 |
{- "results": [
- {
- "id": "string",
- "score": 0,
- "kind": "string",
- "name": "string",
- "path": "string",
- "text": "string"
}
]
}| slug required | string |
| org | string Which tenant's docbrain store to read from. |
{- "slug": "string",
- "org": "string"
}{- "indexed": 0
}| slug required | string |
| q required | string |
| top_k | integer Default: 5 |
{- "results": [
- {
- "id": "string",
- "score": 0,
- "slug": "string",
- "topic": "string",
- "version": "string",
- "text": "string"
}
]
}| path required | string |
{- "path": "string"
}{- "attempted": true,
- "promoted": true,
- "examples_used": 0,
- "candidate_score": 0,
- "baseline_score": 0
}| name required | string |
Tool-specific arguments — see GET /docbrain/tools for each tool's input schema.
{ }The network-reachable counterpart to the stdio agentops-mcp-server binary — what agentops connect --remote <server-url> points a team member's coding tool at instead of a local stdio server. Speaks plain MCP JSON-RPC 2.0 (initialize, tools/list, tools/call) over a single endpoint, one JSON response per POST (no SSE upgrade — this server has no server-initiated push). Only exposes agentops-mcp's tool set (scan/notes/local search) — each tool takes its own path argument, which here must name a connected repo (its RepoConnection id or repo_url, from GET /repos) belonging to the caller's tenant, never a literal filesystem path. A JSON-RPC notification (no id) gets 202 Accepted with no body.
| jsonrpc required | string Value: "2.0" |
| id | any Omit for a notification (gets 202, no response body). |
| method required | string Enum: "initialize" "tools/list" "tools/call" |
| params | object For tools/call: { name: string, arguments: { path: |
{- "jsonrpc": "2.0",
- "id": null,
- "method": "initialize",
- "params": { }
}Registered-but-never-scraped libraries (e.g. auto-discovered from a manifest) are filtered out here — use the list_libraries MCP tool for the full registry.
{- "libraries": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "description": "string",
- "github_repo": "string",
- "docs_url": "string",
- "versions": [
- "string"
], - "doc_snapshots": 0,
- "changelog_versions": 0,
- "total_nodes": 0,
- "last_indexed_at": "2019-08-24T14:15:22Z",
- "used_in_count": 0
}
]
}| slug required | string |
{- "library": {
- "id": 0,
- "slug": "string",
- "name": "string",
- "description": "string",
- "github_repo": "string",
- "docs_url": "string",
- "versions": [
- "string"
], - "doc_snapshots": 0,
- "changelog_versions": 0,
- "total_nodes": 0,
- "last_indexed_at": "2019-08-24T14:15:22Z",
- "used_in_count": 0
}, - "used_in": [
- { }
]
}