Skip to content

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.

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, ...}
Terminal window
curl http://localhost:5050/v1/admin-users/tenant/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "Admin123!", "tenant_id": "default"}'

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}}.

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}.

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.

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
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.

See Limits and Policies.

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.

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}.

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.

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.

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" }
]
}

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?}.

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}.

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

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

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

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

Base: /v1/admin/assets — AI asset registry: CRUD plus POST /v1/admin/assets/sync and GET /v1/admin/assets/export.

Base: /v1/admin/tenants — CRUD plus GET /v1/admin/tenants/{id}/stats. Requires a system-admin token.

The order the reference script uses (dependencies flow downward):

  1. 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.