/api/vai/* and most /api/control/* endpoints return 401 {"detail":"Authentication required"} when called without a valid session or API key. This is verified against auth/guards.py and cc/auth.py.Session auth, /api/auth
src/vailidator/api/auth_routes.pyPOST /api/auth/login no auth
Email + password → session. Sets the HttpOnly vai_session cookie and returns session_token in the body. 401 on bad credentials (no user enumeration); 429 if the per-IP login limit is exceeded.
json request
{ "email": "owner@example.com", "password": "•••••••" }200 response
{ "session_token": "…", "user_id": "…", "email": "…", "name": "…", "status": "active" }POST /api/auth/logout session
Revoke the caller's session and clear cookies. Always 204, does not reveal whether a valid session existed.
GET /api/auth/me session
Return the current user's identity. 401 without a valid session.
Artifacts & receipts, /api/vai
Read-only Control Center data for the dashboard. All require a valid session (cookie or X-Session-Token). Listings paginate with limit (1–200, default 50) + offset.
GET /api/vai/dashboard session
Dashboard summary, KPI block, recent activity, op status.
GET /api/vai/metrics session
Per-type artifact counts and grand total.
GET /api/vai/artifacts session
Paginated artifact listing. Optional artifact_type ∈ {audit_receipt, flight_recorder, memory_receipt, evidence_bundle}, an unknown type returns 400. → {items, total, limit, offset}.
GET /api/vai/artifacts/{artifact_id} session
Fetch one artifact by natural domain id, or 404.
GET /api/vai/receipts session
Audit-receipt listing for the Receipt Explorer (paginated).
Control Center, /api/control
The Control Center data plane authenticates with an X-API-Key (vrf_<prefix>_<secret>, org-scoped). Missing/invalid key → 401; a valid but revoked key → 403 API key has been revoked. A session-based console subset (/api/control/auth/* and some member/settings management) uses org-membership sessions instead.
| Method · Path | Auth | Purpose |
|---|---|---|
POST /api/control/auth/login | credentials | console login (org membership required; 401 on bad creds / no membership) |
GET /api/control/auth/me · POST /auth/logout | session | current console user / logout |
GET /api/control/health | API key | control-plane health |
GET · POST /api/control/sessions · /{id} | API key | recording sessions (Flight Recorder etc.) |
GET · POST /api/control/receipts · /{id} · /{id}/verify | API key | receipts + hash verification |
GET · POST /api/control/evidence · /{id} · /{id}/verify | API key | evidence bundles + verification |
GET · POST /api/control/audits · /{id} | API key | audit runs + dashboard metrics |
GET /api/control/dashboard · /dashboard/{activity,health,projects} | API key | console dashboards |
GET · POST · PATCH /api/control/projects · /{id} | API key | projects |
GET · POST · PATCH · DELETE /api/control/members · /{id} | session (role-aware) | org members + roles |
GET · POST /api/control/users · /{id} | API key / session | users |
GET · PATCH /api/control/settings | session | org settings |
GET /api/control/legal · /legal/{document_name} | API key | legal documents |
python scripts/cc_bootstrap_owner.py (calls create_org_and_key). The full key is printed once: store it securely; only its PBKDF2 hash is persisted.Other authenticated routers
These session-authenticated routers are mounted and return 401 without a valid session. They are catalogued here for completeness; enable and expose only what your deployment needs.
| Prefix | Auth | Scope |
|---|---|---|
/api/orgs/*, /api/invitations/* | session | organizations, members, invitations |
/api/billing/* | session + org-access | plans, checkout, subscriptions, portal, plus POST /api/billing/webhook (no auth; Stripe-signature-verified; 503 if the webhook secret is unset) |
/api/observability/* | session | metrics, events, alerts |
/api/security/* | session | security / reliability / backup / recovery status |