Management API
The management API is a Python FastAPI service. Established tenant-management routes and mounted-but-provisional operator read contracts share one process. A mounted route is not production operator readiness.
Base URL and contract artifacts
Local default: http://127.0.0.1:8010.
GET /openapi.json,/docs,/redocGET /health,/ready,/metricsGET /v1/tenant/ping— authenticated tenant smoke route
The mounted route inventory is generated from the FastAPI app and checked in under services/api/scripts/route_inventory.json. The OpenAPI snapshot is checked separately. Both must be regenerated when a route or schema changes.
services/api/.venv/bin/python services/api/scripts/route_inventory.py --check
bash .github/scripts/check-openapi-snapshot.sh
Two authentication modes
| Mode | Used by | Rules |
|---|---|---|
| Bearer PAT | Tenant management routes | Permission bitmap, path org must match the token org, role checks where declared |
| Operator cookie | Console-facing D1/D2 and operator session routes | Server-owned access/refresh cookies, CSRF on cookie mutations, session subject and permissions |
A browser bearer token is not an alternative operator-session design. Operator session issuance is default-off and requires the auth/session feature path; the development HS256 stub is not a production issuer. See Operator sessions.
Route families
| Family | Mounted paths | Boundary |
|---|---|---|
| Organizations | GET/PATCH /v1/organizations/{org_id}, POST .../suspend, DELETE ... | Role/permission check; deletion returns 202 and a job |
| Deletion jobs | GET /v1/organizations/{org_id}/deletion-jobs/{job_id} | Owner/admin read; per-store receipts |
| Users | GET/POST /v1/users, GET/PATCH/DELETE /v1/users/{user_id} | Last-owner protection; admin/owner rules |
| Agents | GET/POST /v1/agents, GET/PATCH/DELETE /v1/agents/{agent_id}, `POST .../{agent_id}/activate | pause |
| Tokens | GET/POST /v1/tokens, GET/DELETE /v1/tokens/{token_id} | Plaintext returned only at creation; never re-readable |
| Providers | GET/POST /v1/organizations/{org_id}/providers, DELETE .../{provider_name} | Metadata only; secret sealing delegated to auth |
| Rate limits | GET/PATCH /v1/organizations/{org_id}/rate-limits | Org and per-agent RPM overrides |
| Model policies | GET/POST /v1/organizations/{org_id}/model-policies, GET/PATCH/DELETE .../{policy_id} | Tenant policy CRUD; proxy enforces the resolved policy |
| Capture policies | GET/POST /v1/organizations/{org_id}/capture-policies, GET .../resolved, PATCH/DELETE .../{policy_id} | Retention/redaction policy CRUD and resolution |
| Billing | GET/POST .../rate-cards, POST .../rate-cards/{card_id}/versions, GET/POST .../budget-periods | Versioned rates, immutable published versions |
| Usage | POST /v1/organizations/{org_id}/usage/query | Token-scoped; requires an org predicate in generated ClickHouse SQL |
| Legal holds | GET/POST .../legal-holds, POST .../{hold_id}/clear | LegalHoldManage; set/clear require a session subject |
| Operator session | `POST /v1/operator/session/login | refresh |
| Operator D1 | GET /v1/operator/context, /overview, /platform/health, /events/stream | Read/event transport; provisional |
| Operator D2 | GET /v1/operator/traces, /traces/{trace_id}, /traces/runs/{run_id} | Metadata-only list and deterministic multi-run read |
The D2 list uses an opaque, signed cursor and a bounded time range; invalid or expired cursors are VALIDATION_ERROR, not a silent restart. A trace lookup that is unknown or outside the tenant returns NOT_FOUND.
Authorization sequence
- Authenticate the credential (PAT bearer or operator session).
- For a path-scoped route, compare the path
org_idwith the verified organization. - Check the required permission bit or role.
- Open a tenant-scoped database session and set
app.current_org_idfor the transaction. - Apply explicit
org_idpredicates even where RLS is enabled. - Map missing or cross-tenant resources to
404where existence leakage is a risk.
A path mismatch is not permission to use the path organization. The token's organization wins, and the request is rejected.
Example: list token metadata
curl -s \
-H "Authorization: Bearer ${IBEX_DEV_TOKEN}" \
"http://127.0.0.1:8010/v1/tokens"
A token response returns metadata such as ID, name, type, permissions, and timestamps. It never returns the plaintext secret after creation. Do not put the token in a URL.
Error behavior
| Condition | HTTP | Code examples |
|---|---|---|
| Missing/invalid credential | 401 | Authentication failure from the auth layer |
| Missing permission or role | 403 | INSUFFICIENT_PERMISSIONS |
| Step-up required | 403 | INSUFFICIENT_PERMISSIONS with step-up detail |
| Path org mismatch | 403 | INSUFFICIENT_PERMISSIONS |
| Unknown/cross-tenant resource | 404 | NOT_FOUND |
| Invalid input, cursor, or query range | 400 | VALIDATION_ERROR |
| Last owner removal | 409 | LAST_OWNER_PROTECTED |
| Dependency/store unavailable | 503 | SERVICE_DEGRADED |
The shared error envelope is defined by the API error package; do not return ad-hoc JSON. A 202 deletion response is an accepted request, not a completed purge.
Operator D1/D2 boundary
D1/D2 are read-only and return Cache-Control: no-store. D2 exposes approved run metadata only: no prompts, completions, hidden reasoning, raw tool arguments, or unredacted payloads. The Console must not fabricate a detail when the upstream returns unavailable.
The API has no general provenance inspector, replay action, export endpoint, or operator write tool in this slice. Mounted presentation in the Console is not an owning contract.
Configuration
| Variable | Purpose |
|---|---|
IBEX_API_DATABASE_URL | Async PostgreSQL DSN |
IBEX_AUTH_GRPC_ADDR / IBEX_API_AUTH_GRPC_ADDR | AuthService gRPC target |
IBEX_API_AUTH_TIMEOUT_MS | Auth deadline; default 50 ms |
IBEX_API_REDIS_URL | Suspension/rate-limit pub/sub and idempotency support |
IBEX_API_CELERY_BROKER_URL | Required for organization-deletion enqueue; fail closed |
IBEX_API_HOST / IBEX_API_PORT | Bind settings; default port 8010 |
IBEX_API_DOCS_BASE_URL | Public error-docs prefix |
DASHBOARD_JWT_PUBLIC_KEYS_PEM | Operator-session RS256 verification keys; distinct from auth issuer keys |
Operator session feature flags and TOTP settings belong to the auth/API session path; do not infer them from a Console environment variable.
Readiness boundary
Production promotion still requires AuthService/session/MFA integration, deployment-origin and CORS/CSRF evidence, two-tenant negative tests, redaction and hostile-content tests, performance/availability evidence, and rollback/incident runbooks. The full management product and provenance inspector are not complete until those gates are accepted.
Related
- Operator sessions — cookie and step-up contract
- Responses — data-plane response shapes
- Data lifecycle and deletion —
202, receipts, and holds - Billing and budgets — rate cards and reservation limits
- Console — how the read slices are presented
- Tenant isolation — path mismatch and 404 rules

