Admin API
All configuration writes go through the Control Plane (:5050) — the Python/FastAPI admin plane that backs the Admin UI and owns the database schema. Runtime traffic never touches it.
| Base URL | http://localhost:5050 (admin resources under /v1/admin/...) |
| Auth | Authorization: Bearer <token> from tenant-admin login. Tenant admins are auto-scoped by their token (no X-Tenant-ID needed). System admins pass a tenant_id query param on some endpoints. |
| Interactive docs | http://localhost:5050/docs on a running Control Plane — full OpenAPI with every field and schema |
This page is the endpoint map plus the essential create-body fields. For a complete, runnable provisioning sequence see Setup Scripts and the reference script brutor-demo-mcp/setup-llm-demo.py.
Idempotency conventions
Section titled “Idempotency conventions”Admin endpoints follow consistent patterns that make setup scripts safely re-runnable:
| Pattern | Behavior |
|---|---|
| Check-then-create | GET list with ?search=<name> first; POST only if absent; treat 409 Conflict as “already exists” and re-fetch the id |
PATCH sub-documents |
Full-replace, converge-to-desired-state — send the complete desired sub-document, not a delta |
Binding POSTs |
Idempotent — 409 (already bound) and 404 (already unbound) are tolerated |
| Seeds | Create-once: never stomp rows an operator may have edited in the Admin UI |
| Method | Path | Body | Response |
|---|---|---|---|
| POST | /v1/admin-users/tenant/login |
{username, password, tenant_id?} |
{access_token, ...} |
| POST | /v1/admin-users/system/login |
{username, password} |
{access_token, ...} |
curl http://localhost:5050/v1/admin-users/tenant/login \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "Admin123!", "tenant_id": "default"}'End users
Section titled “End users”Base: /v1/admin/end-users
| Method | Path | Purpose | Idempotency |
|---|---|---|---|
| GET | /v1/admin/end-users |
List (?search&active_only&limit&offset) |
— |
| GET | /v1/admin/end-users/{id} |
Detail | — |
| POST | /v1/admin/end-users |
Create | 409 on duplicate → re-fetch by ?search= |
| PATCH | /v1/admin/end-users/{id}/status |
{is_active} |
Converges |
| PATCH | /v1/admin/end-users/{id}/primary-group |
{group_id} |
Converges |
| DELETE | /v1/admin/end-users/{id} |
Delete | 404-tolerant |
| POST | /v1/admin/end-users/{id}/photo |
Upload photo | Replaces |
| GET | /v1/admin/end-users/export/csv | /export/json |
Export | — |
Create body: {username, password, email, display_name, send_welcome_email} → response contains {user: {id}}.
End-user groups
Section titled “End-user groups”Base: /v1/admin/end-user-groups
| Method | Path | Purpose | Idempotency |
|---|---|---|---|
| GET/POST/PATCH/DELETE | /v1/admin/end-user-groups (+/{id}) |
CRUD (GET ?search=) |
409-tolerated create |
| POST | /v1/admin/end-user-groups/{id}/members |
Add members {end_user_ids: [...]} |
Re-assert safe |
| DELETE | /v1/admin/end-user-groups/{id}/members |
Remove members | 404-tolerant |
| PUT | /v1/admin/end-user-groups/{id}/members |
Authoritative set — replaces membership | Converges |
| POST/DELETE | /v1/admin/end-user-groups/{id}/resource-groups |
Bind/unbind to resource groups | 409/404-tolerated |
Create body: {name, display_name, description, initial_member_ids} → {id}.
Resource groups
Section titled “Resource groups”Base: /v1/admin/resource-groups. Concepts: Resource Groups.
| Method | Path | Purpose | Idempotency |
|---|---|---|---|
| GET/POST/PATCH/DELETE | /v1/admin/resource-groups (+/{id}) |
CRUD (?search&parent_id&group_type) |
409-tolerated create |
| GET | /v1/admin/resource-groups/{id}/hierarchy |
Full tree | — |
| GET | /v1/admin/resource-groups/{id}/ancestors |
Ancestor chain | — |
| GET | /v1/admin/resource-groups/{id}/descendants |
Descendants | — |
Create body: {name, display_name, description, group_type: "organization"|"team", inherit_resources: bool, parent_group_id?, eu_ai_act_risk_tier?, phi_resource?} → {id}. Create parents before children.
Bindings
Section titled “Bindings”| Method | Path | Purpose | Idempotency |
|---|---|---|---|
| POST/DELETE/GET | /v1/admin/resource-groups/{id}/llm-models |
Bind/unbind/list LLM models | 409/404-tolerated |
| PATCH | /v1/admin/resource-groups/{id}/llm-models/{model}/portal-visibility |
{portal_visible} — portal picker visibility only (not access) |
Converges |
| POST | /v1/admin/server-configs |
Grant MCP server access — body {mcp_server_id, group_ids, ...} (server-config binding, not an RG sub-path) |
409-tolerated |
| GET | /v1/admin/resource-groups/{id}/effective-server-configs |
List MCP servers effective for the group (incl. inherited) | — |
| POST/DELETE/GET | /v1/admin/resource-groups/{id}/end-user-groups |
Bind end-user groups {end_user_group_ids: [...]} |
409-tolerated |
API keys
Section titled “API keys”| Method | Path | Purpose |
|---|---|---|
| GET | /v1/admin/resource-groups/{id}/api-keys |
List keys for the group |
| POST | /v1/admin/resource-groups/{id}/api-keys |
Create — body {name, access_mode: "shared"} |
The plaintext key is returned once in the create response (key_value / full_key / key) — capture it immediately (the demo script writes keys to a .env-style file). See Users and API Keys.
Limits, governance, compliance sub-documents
Section titled “Limits, governance, compliance sub-documents”All are PATCH full-replace — send the complete desired state.
| Method | Path | Body (essential fields) |
|---|---|---|
| PATCH | /v1/admin/resource-groups/{id}/llm-global-limits |
{llm_global_limits: {tokens: {daily_limit}, throughput: {max_requests_per_minute, cooldown_seconds, max_usd_per_minute}, concurrency: {max_concurrent}}} |
| PATCH | /v1/admin/resource-groups/{id}/llm-global-governance |
{governance: {temperature: {max, enforce: "clamp"}, context_window: {max_output_tokens, enforce: "clamp"}}} |
| PATCH | /v1/admin/resource-groups/{id}/mcp-global-limits |
MCP-side limits |
| PATCH | /v1/admin/resource-groups/{id}/mcp-servers/{server_id}/limits |
Per-server MCP limit refinements |
Per-group compliance flags (eu_ai_act_risk_tier, phi_resource) are set with the plain PATCH /v1/admin/resource-groups/{id} — there is no separate compliance sub-endpoint. See Compliance.
LLM models
Section titled “LLM models”Base: /v1/admin/llms
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/admin/llms |
List (?mode=chat|embedding|routing&provider_key) |
| GET/POST/PATCH/DELETE | /v1/admin/llms (+/{id}) |
CRUD |
| POST | /v1/admin/llms/{id}/health-check |
Probe one model |
| POST | /v1/admin/llms/bulk-health-check |
Probe all |
Create body (plain create): {name, model_name, mode: "chat"|"embedding", provider, enabled, api_key?, default_temperature, default_max_tokens, system_prompt, routing_group_id?, routing_weight, group_ids}. routing_weight: 0 = fallback, ≥1 = active. Prefer catalog import — it copies cost data.
GET /v1/admin/llms?mode=routing returns routing groups’ virtual models — bind these to resource groups to expose the routing group.
Routing groups
Section titled “Routing groups”Base: /v1/admin/llm-router/routing-groups — CRUD (GET ?enabled_only=false).
Create body: {id (user-chosen slug), name, description, mode: "chat", routing_strategy: "simple-shuffle", enabled, allowed_fails, cooldown_time, cooldown_window, num_retries, retry_after, timeout}.
Providers
Section titled “Providers”Base: /v1/admin/providers — CRUD for per-tenant LLM providers. The global provider catalog auto-imports into the tenant on model add, so you rarely create providers directly.
LLM catalog
Section titled “LLM catalog”Base: /v1/admin/llm-catalog
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/admin/llm-catalog |
Global catalog (?provider_key=&mode=&limit=500) |
| POST | /v1/admin/llm-catalog/{catalog_id}/import |
Import into the tenant — body {name, enabled, group_ids, api_key?}; copies cost data |
Post-import, PATCH /v1/admin/llms/{id} for routing membership and parameter defaults.
Guardrails
Section titled “Guardrails”Base: /v1/admin/guardrails/configs — CRUD. PATCH is full-replace of surfaces / builtin / providers. Concepts: Guardrails.
Create body (essential structure):
{ "name": "default-guardrails", "description": "...", "enabled": true, "group_ids": ["rg_..."], "surfaces": { "chat_input": true, "chat_output": true, "embeddings_input": false, "image_gen_input": false, "image_gen_output": false, "audio_tts_input": false, "audio_tts_output": false, "audio_stt_input": false, "audio_stt_output": false, "video_gen_input": false, "video_gen_output": false, "batch_input": false, "batch_output": false, "moderation_input": false, "mcp_input": true, "mcp_output": true, "mcp_registration": false, "skill_input": false, "skill_output": false, "a2a_inbound": false, "a2a_outbound": false }, "builtin": { "prompt_injection_enabled": true, "prompt_injection_action": "block", "prompt_injection_surfaces": ["chat_input"], "jailbreak_enabled": true, "pii_enabled": true, "pii_action": "redact", "pii_provider": "built_in", "pii_categories": ["email", "phone", "credit_card", "ssn", "iban"], "pii_surfaces": ["chat_input", "chat_output"], "pii_threshold": 0.5, "toxic_content_enabled": true, "toxic_content_action": "block", "toxic_content_threshold": 0.8, "toxic_content_surfaces": ["chat_input"], "secrets_enabled": true, "secrets_action": "block", "secrets_categories": ["aws_access_key", "github_token", "openai_key", "jwt", "private_key_pem"], "secrets_surfaces": ["chat_input", "chat_output"], "banned_words": [], "banned_words_surfaces": [] }, "providers": [ { "provider": "presidio", "enabled": false, "endpoint": "http://presidio-analyzer:3030" } ]}Semantic policies (LLM-judge)
Section titled “Semantic policies (LLM-judge)”Base: /v1/admin/semantic-policies — CRUD.
Create body: {name, description, constraint_text (natural language), action: "block"|"warn", mode: "enforce"|"shadow", surfaces: ["chat_input", ...], resource_group_ids?}.
Argument policies
Section titled “Argument policies”Base: /v1/admin/argument-policies — CRUD, plus POST /v1/admin/argument-policies/{id}/groups to bind groups.
Create body: {name, description, surface: "llm_output_tool_calls", target: "<tool name>", argument_key: "sql", analyzer: "sql", severity: "deny"|"warn", enabled, rules: [{deny_if: "writes"|"multi_statement"|..., message, values?}], group_ids}.
Semantic cache
Section titled “Semantic cache”Base: /v1/admin/semantic-cache/configs — CRUD, plus group binding and invalidation.
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/admin/semantic-cache/configs |
{name, enabled, exact_match: {enabled, ttl_seconds}, semantic_match: {enabled, similarity_threshold, ttl_seconds}} |
| POST | /v1/admin/semantic-cache/configs/{id}/groups?replace=true |
Bind — {group_ids} |
| POST | /v1/admin/semantic-cache/configs/.../invalidate |
Invalidate cached entries |
MCP servers
Section titled “MCP servers”Base: /v1/admin/mcp-servers. Guide: Register an MCP Server.
| Method | Path | Purpose |
|---|---|---|
| GET/POST/PATCH/DELETE | /v1/admin/mcp-servers (+/{id}) |
CRUD |
| POST | /v1/admin/mcp-servers/test-connection |
Pre-create connectivity test |
| POST | /v1/admin/mcp-servers/{id}/health-check |
Probe |
| POST | /v1/admin/mcp-servers/{id}/refresh-capabilities |
Re-fetch tools/resources/prompts |
| POST | /v1/admin/mcp-servers/{id}/icon |
Upload icon |
Compliance
Section titled “Compliance”Base: /v1/admin/compliance. Concepts: Compliance.
| Method | Path | Purpose |
|---|---|---|
| GET/PATCH | /v1/admin/compliance/profile |
{frameworks: [...]} — full-replace; valid keys: soc2, eu_ai_act, hipaa, gdpr_art_30, iso_42001, opt-in per tenant |
| GET | /v1/admin/compliance/dashboard |
Compliance dashboard data |
| GET | /v1/admin/compliance/gdpr/article-30?format=csv|json |
GDPR Art. 30 record of processing |
| GET | /v1/admin/compliance/eu-ai-act/risk-classification |
EU AI Act risk report |
| GET | /v1/admin/compliance/soc2/control-coverage |
SOC 2 control coverage |
| GET | /v1/admin/compliance/hipaa/phi-access |
HIPAA PHI access report |
| GET | /v1/admin/compliance/iso-42001/activity |
ISO 42001 activity report |
Usage import (Traffic Data Import)
Section titled “Usage import (Traffic Data Import)”Base: /v1/admin/usage-import — import vendor admin/analytics telemetry into the usage ledger.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/admin/usage-import/providers |
List (?only_supported=true) |
| GET | /v1/admin/usage-import/providers/{id} |
Detail |
| PATCH | /v1/admin/usage-import/providers/{id} |
{import_enabled, import_schedule_cron, import_mapping_policy: {mode: "auto_create"}, import_backfill_through, import_endpoint_override?, api_key?} |
| POST | /v1/admin/usage-import/providers/{id}/run |
Manual run |
| GET | /v1/admin/usage-import/providers/{id}/runs |
Run history |
| POST | /v1/admin/usage-import/providers/{id}/test |
Connectivity test |
Assets
Section titled “Assets”Base: /v1/admin/assets — AI asset registry: CRUD plus POST /v1/admin/assets/sync and GET /v1/admin/assets/export.
Tenants (system admin only)
Section titled “Tenants (system admin only)”Base: /v1/admin/tenants — CRUD plus GET /v1/admin/tenants/{id}/stats. Requires a system-admin token.
Recommended provisioning order
Section titled “Recommended provisioning order”The order the reference script uses (dependencies flow downward):
- End users → 2. End-user groups (+ members) → 3. Resource groups (parents first, then end-user-group bindings) → 4. Routing groups → 5. LLM models (catalog import, then RG bindings — including the routing group’s virtual model) → 6. API keys (capture plaintext once) → 7. Guardrails → 8. Param governance → 9. Usage limits → 10. Semantic cache → 11. Argument policies → 12. Semantic policies → 13. Compliance profile → 14. Asset sync → 15. Traffic data import.
Full walkthrough: Setup Scripts.
