{"openapi":"3.1.0","info":{"title":"erabot.ai API","description":"AI Code Cost Analysis & Optimization Platform.\n\nScan codebases, analyze LLM token usage and API costs, and get AI-powered recommendations\nto reduce spending — with actionable diffs you can apply directly.\n\n## Authentication\n\nerabot.ai uses two authentication methods depending on the endpoint:\n\n### 1. JWT Cookie Auth (Dashboard / Web UI)\nMost endpoints use HTTP-only JWT cookies set via `POST /auth/login`.\nThe cookie is automatically included in subsequent requests from the browser.\n\n### 2. Bearer Token Auth (API / SDK / CLI)\nProgrammatic access uses API keys passed as `Authorization: Bearer <api-key>`.\nGenerate API keys from the dashboard under Settings > API Keys.\n\n### 3. Client Attribution Header\nFor proxy requests, include `X-Erabot-Client: <client-uuid>` to attribute\nusage to a specific client for per-client analytics and budget enforcement.\n","version":"0.1.0"},"paths":{"/v1/chat/completions":{"post":{"tags":["proxy"],"summary":"Chat Completions","description":"OpenAI-compatible chat completions endpoint.","operationId":"chat_completions_v1_chat_completions_post","parameters":[{"name":"x-erabot-client","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Erabot-Client"}},{"name":"x-erabot-prompt-template","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Erabot-Prompt-Template"}},{"name":"x-erabot-conversation-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Erabot-Conversation-Id"}},{"name":"x-erabot-context-mode","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Erabot-Context-Mode"}},{"name":"x-erabot-context-target","in":"header","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"X-Erabot-Context-Target"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embeddings":{"post":{"tags":["proxy"],"summary":"Embeddings","description":"OpenAI-compatible embeddings endpoint.","operationId":"embeddings_v1_embeddings_post","parameters":[{"name":"x-erabot-client","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Erabot-Client"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models":{"get":{"tags":["proxy"],"summary":"List Models","description":"OpenAI-compatible models list endpoint.","operationId":"list_models_v1_models_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/overview":{"get":{"tags":["analytics"],"summary":"Get Usage Overview","description":"Get overall usage statistics for a project.","operationId":"get_usage_overview_api_analytics_overview_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageOverview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/by-model":{"get":{"tags":["analytics"],"summary":"Get Usage By Model","description":"Get usage breakdown by model.","operationId":"get_usage_by_model_api_analytics_by_model_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/trends":{"get":{"tags":["analytics"],"summary":"Get Usage Trends","description":"Get daily usage trends.","operationId":"get_usage_trends_api_analytics_trends_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/distribution":{"get":{"tags":["analytics"],"summary":"Get Token Distribution","description":"Get input vs output token distribution by model.","operationId":"get_token_distribution_api_analytics_distribution_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TokenDistribution"},"title":"Response Get Token Distribution Api Analytics Distribution Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/efficiency":{"get":{"tags":["analytics"],"summary":"Get Latency Efficiency","description":"Analyze cost vs latency efficiency.","operationId":"get_latency_efficiency_api_analytics_efficiency_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LatencyEfficiency"},"title":"Response Get Latency Efficiency Api Analytics Efficiency Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/savings-trends":{"get":{"tags":["analytics"],"summary":"Get Savings Trends","description":"Get daily trends of actual cost vs savings.","operationId":"get_savings_trends_api_analytics_savings_trends_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SavingsOverTime"},"title":"Response Get Savings Trends Api Analytics Savings Trends Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/project-comparison":{"get":{"tags":["analytics"],"summary":"Get Project Comparison","description":"Compare costs and savings across all projects owned by the current user.","operationId":"get_project_comparison_api_analytics_project_comparison_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectComparison"},"title":"Response Get Project Comparison Api Analytics Project Comparison Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/audit":{"post":{"tags":["analytics"],"summary":"Audit Codebase","description":"Scan and audit a local codebase for LLM inefficiencies.\n\nUses RAG-enhanced analysis with:\n- Actionable strategies (hand-crafted optimization patterns)\n- Academic research from arXiv (cutting-edge techniques)","operationId":"audit_codebase_api_analytics_audit_post","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/quick-advice":{"post":{"tags":["analytics"],"summary":"Get Quick Advice","description":"Get instant optimization advice using RAG knowledge base.\n\nIdeal for:\n- Quick questions about optimization techniques\n- Analyzing small code snippets\n- Getting recommendations before an audit","operationId":"get_quick_advice_api_analytics_quick_advice_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickAdviceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickAdviceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/knowledge-base/stats":{"get":{"tags":["analytics"],"summary":"Get Knowledge Base Stats","description":"Get statistics about the RAG knowledge base.","operationId":"get_knowledge_base_stats_api_analytics_knowledge_base_stats_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/knowledge-base/refresh":{"post":{"tags":["analytics"],"summary":"Refresh Knowledge Base","description":"Refresh the knowledge base by re-ingesting all sources.\n\nThis should be called after adding new knowledge files:\n- strategies.md (actionable optimization strategies)\n- arxiv_research.md (academic papers from arXiv)","operationId":"refresh_knowledge_base_api_analytics_knowledge_base_refresh_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/top-prompts":{"get":{"tags":["analytics"],"summary":"Get Top Prompts","description":"Get highest-cost prompt templates.","operationId":"get_top_prompts_api_analytics_top_prompts_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/prompt-templates":{"get":{"tags":["analytics"],"summary":"Get Prompt Template Stats","description":"Per-prompt template cost and quality metrics.","operationId":"get_prompt_template_stats_api_analytics_prompt_templates_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplatesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/recommendations":{"get":{"tags":["analytics"],"summary":"Get Optimization Recommendations","description":"Get cost optimization recommendations.","operationId":"get_optimization_recommendations_api_analytics_recommendations_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/audit-summary":{"get":{"tags":["analytics"],"summary":"Get Audit Summary","description":"Get the latest audit report summary for a project.","operationId":"get_audit_summary_api_analytics_audit_summary_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/audit-export/{audit_id}":{"get":{"tags":["analytics"],"summary":"Export Audit For Agent","description":"Export audit report as a CLAUDE.md-compatible agent instruction file.","operationId":"export_audit_for_agent_api_analytics_audit_export__audit_id__get","parameters":[{"name":"audit_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Audit Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/audit-pdf/{audit_id}":{"get":{"tags":["analytics"],"summary":"Export Audit Pdf","description":"Export audit report as PDF.","operationId":"export_audit_pdf_api_analytics_audit_pdf__audit_id__get","parameters":[{"name":"audit_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Audit Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/executive-summary":{"get":{"tags":["analytics"],"summary":"Get Executive Summary","description":"Executive-level cost summary: monthly trend (12 months), by-team breakdown,\nsavings captured/potential, current/prev/projected month costs.","operationId":"get_executive_summary_api_analytics_executive_summary_get","parameters":[{"name":"project_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecSummaryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/analytics/knowledge-base/health":{"get":{"tags":["analytics"],"summary":"Knowledge Base Health","description":"Knowledge base health check -- reports staleness, chunk count, refresh status.\n\nPer Pitfall 5: provides observability into KB health so stale data is detected.\nNo authentication required (health check endpoint).","operationId":"knowledge_base_health_api_analytics_knowledge_base_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/log":{"post":{"tags":["logging"],"summary":"Receive Logs","description":"Receive usage logs from Erabot SDK.\n\nRequires authentication via Bearer token (AUTH-05).\nAccepts batched logs for efficiency.","operationId":"receive_logs_v1_log_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogBatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/log/stats":{"get":{"tags":["logging"],"summary":"Get Log Stats","description":"Get basic stats about logged usage. Requires authentication (AUTH-05).","operationId":"get_log_stats_v1_log_stats_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/log/apps/{app_id}":{"get":{"tags":["logging"],"summary":"Get App Stats","description":"Get detailed stats for a specific app. Requires authentication (AUTH-05).\n\nScoped to the authenticated user's data to prevent IDOR (AUTH-06).","operationId":"get_app_stats_v1_log_apps__app_id__get","parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","title":"App Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/register":{"post":{"tags":["auth"],"summary":"Register","description":"Register a new agency account. Sets HTTP-only JWT cookie on success.\n\nPhase 56 LAUNCH-08: if a ``try_session_id`` cookie is present on the\nsignup request, any anonymous scan_jobs rows tied to that session are\nmigrated to the new user's id BEFORE the cookie is cleared — so the\nuser can immediately download agent-instructions.md for the scan they\njust ran without being authenticated.\n\nPhase 56 LAUNCH-39 (Plan 08): the ``signups_paused`` kill switch is\nchecked BEFORE any DB writes so an on-call operator can stop new\nuser creation in <30 seconds via the admin dashboard without a\nredeploy. Returns HTTP 503 with ``error: signups_paused`` body.","operationId":"register_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/login":{"post":{"tags":["auth"],"summary":"Login","description":"Log in with email and password. Sets HTTP-only JWT cookie on success.","operationId":"login_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"Log out by clearing the JWT cookie server-side.","operationId":"logout_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/me":{"get":{"tags":["auth"],"summary":"Me","description":"Return the authenticated user's profile.","operationId":"me_auth_me_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/forgot-password":{"post":{"tags":["auth"],"summary":"Forgot Password","description":"Request a password reset email. Always returns 200 to prevent email enumeration.","operationId":"forgot_password_auth_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/reset-password":{"post":{"tags":["auth"],"summary":"Reset Password","description":"Reset password using a valid reset token.","operationId":"reset_password_auth_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/verify-email/{token}":{"get":{"tags":["auth"],"summary":"Verify Email","description":"Verify an email-verification token and mark the user verified.\n\nIdempotent: re-verifying an already-verified user returns a 200 ok\nwithout writing to the DB. Invalid/expired tokens return 400.","operationId":"verify_email_api_auth_verify_email__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/verify-email/send":{"post":{"tags":["auth"],"summary":"Resend Verification Email","description":"Mint a fresh verification token and email it to the signed-in user.\n\nIf the user is already verified, this is a no-op success. We never\nleak provider errors: if the send fails, return status=queued so the\nUI can safely show 'check your inbox'.","operationId":"resend_verification_email_api_auth_verify_email_send_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Resend Verification Email Api Auth Verify Email Send Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/metrics":{"get":{"tags":["admin"],"summary":"Get Admin Metrics","description":"Return the 8-panel launch-day admin metrics dashboard payload.\n\nGated behind ``require_admin`` so only users with ``is_admin=True``\ncan reach it. Polled by the frontend admin dashboard every 60\nseconds (see ``frontend/app/(app)/dashboard/admin/page.tsx``).\n\nThe response shape is stable — do NOT rename keys without also\nupdating the frontend ``AdminMetrics`` interface.","operationId":"get_admin_metrics_api_admin_metrics_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Admin Metrics Api Admin Metrics Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/kill-switches":{"get":{"tags":["admin"],"summary":"List Kill Switches","description":"Return the current state of all 3 kill switches.\n\nResponse shape: ``{\"signups_paused\": false, \"scans_paused\": false,\n\"github_prs_paused\": false}``. Fail-open on Redis error — see\n``services/kill_switches.py::is_killed`` for the rationale.","operationId":"list_kill_switches_api_admin_kill_switches_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response List Kill Switches Api Admin Kill Switches Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/admin/kill-switch/{name}":{"post":{"tags":["admin"],"summary":"Toggle Kill Switch","description":"Flip a named kill switch on or off.\n\nRequest body: ``{\"enabled\": true/false}``. Returns the new state.\n\nRaises:\n    404 if ``name`` is not one of the 3 registered kill switches.\n    503 if Redis is unavailable (the toggle cannot be persisted).","operationId":"toggle_kill_switch_api_admin_kill_switch__name__post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Toggle Kill Switch Api Admin Kill Switch  Name  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/account/data":{"delete":{"tags":["account"],"summary":"Delete Account Data","description":"Cascade hard-delete the user's child rows + SOFT-delete the user row.\n\nOrder of operations (required to avoid FK violations):\n\n1. Delete any ``scan_findings`` rows referencing the user's scan jobs\n   (table may not exist — wrap in try/except). In the current schema,\n   findings are stored as JSON inside ``scan_jobs.findings``, so this\n   is a no-op on most deployments.\n2. Delete any ``llm_calls`` rows owned by the user (table may not\n   exist — wrap in try/except).\n3. Delete the user's ``scan_jobs`` rows.\n4. Delete the user's ``user_tiers`` row (tier / subscription linkage).\n5. SOFT-delete the users row itself: replace email with a per-user\n   placeholder and set ``deleted_at`` to the current UTC timestamp.\n\nStripeEvent rows are intentionally retained. They reference events\nby ``stripe_event_id`` and not by ``user_id``, so they do not expose\nPII on their own and must stay for financial audit compliance.\n\nReturns a small JSON payload confirming deletion and the timestamp.","operationId":"delete_account_data_api_account_data_delete","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Delete Account Data Api Account Data Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/clients":{"post":{"tags":["clients"],"summary":"Create Client","description":"Create a new named client for this agency. CLIENT-01, CLIENT-05.","operationId":"create_client_api_clients_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["clients"],"summary":"List Clients","description":"List all non-archived clients with their MTD spend ranked by cost. CLIENT-02, ATTR-03.","operationId":"list_clients_api_clients_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientWithMTD"},"title":"Response List Clients Api Clients Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/clients/{client_id}/analytics":{"get":{"tags":["clients"],"summary":"Get Client Analytics","description":"Return cost rollup for a client over a date range. ATTR-02.","operationId":"get_client_analytics_api_clients__client_id__analytics_get","parameters":[{"name":"client_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Client Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientAnalytics"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/clients/{client_id}/analytics/projects":{"get":{"tags":["clients"],"summary":"Get Client Project Breakdown","description":"Return per-project cost breakdown within a client. ATTR-05.","operationId":"get_client_project_breakdown_api_clients__client_id__analytics_projects_get","parameters":[{"name":"client_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Client Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectBreakdown"},"title":"Response Get Client Project Breakdown Api Clients  Client Id  Analytics Projects Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/clients/{client_id}/export/csv":{"get":{"tags":["clients"],"summary":"Export Client Csv","description":"Export client usage records as CSV for a date range. REPORT-01.","operationId":"export_client_csv_api_clients__client_id__export_csv_get","parameters":[{"name":"client_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Client Id"}},{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date","description":"Start of date range (inclusive), ISO-8601","title":"Start Date"},"description":"Start of date range (inclusive), ISO-8601"},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date","description":"End of date range (inclusive), ISO-8601","title":"End Date"},"description":"End of date range (inclusive), ISO-8601"},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/clients/{client_id}/report/pdf":{"post":{"tags":["clients"],"summary":"Generate Client Pdf","description":"Generate a white-label PDF report for a client. REPORT-02, REPORT-03, REPORT-04.","operationId":"generate_client_pdf_api_clients__client_id__report_pdf_post","parameters":[{"name":"client_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Client Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PDFReportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/clients/{client_id}":{"patch":{"tags":["clients"],"summary":"Update Client","description":"Update a client's name, budget cap, or fallback model. CLIENT-03.","operationId":"update_client_api_clients__client_id__patch","parameters":[{"name":"client_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Client Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["clients"],"summary":"Archive Client","description":"Soft-delete a client by setting is_archived=True. Data is retained. CLIENT-04.","operationId":"archive_client_api_clients__client_id__delete","parameters":[{"name":"client_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Client Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/projects":{"get":{"tags":["projects"],"summary":"List Projects","description":"Return all projects owned by the authenticated agency. ATTR-04.","operationId":"list_projects_api_projects_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"},"title":"Response List Projects Api Projects Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["projects"],"summary":"Create Project","description":"Create a new project, optionally linked to a client.","operationId":"create_project_api_projects_post","parameters":[{"name":"client_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Client Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/projects/{project_id}":{"delete":{"tags":["projects"],"summary":"Delete Project","description":"Delete a project owned by the current user.","operationId":"delete_project_api_projects__project_id__delete","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/keys":{"get":{"tags":["keys"],"summary":"List Keys","description":"List all API keys for the authenticated user, joined with project name.","operationId":"list_keys_api_keys_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/APIKeyResponse"},"title":"Response List Keys Api Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["keys"],"summary":"Create Key","description":"Create a new API key for the authenticated user.\n\nIf no project_id is provided, auto-creates a Client + Project from the key name\nso the dashboard has something to display immediately.","operationId":"create_key_api_keys_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIKeyCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIKeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/keys/detect-providers":{"post":{"tags":["keys"],"summary":"Detect Providers","description":"Scan a code path, detect LLM providers used. Never returns actual API key values.","operationId":"detect_providers_api_keys_detect_providers_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/keys/{key_id}":{"delete":{"tags":["keys"],"summary":"Delete Key","description":"Delete an API key owned by the current user.","operationId":"delete_key_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/keys/{key_id}/provider-key":{"patch":{"tags":["keys"],"summary":"Update Provider Key","description":"Update the provider API key for an existing key.","operationId":"update_provider_key_api_keys__key_id__provider_key_patch","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIKeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/demo":{"get":{"tags":["scans"],"summary":"Get Public Demo Scan","description":"Return a public read-only demo scan for landing-page tours.\n\nPicks the highest-savings completed scan belonging to the seeded\n``visa-demo@erabot.ai`` account (see backend/scripts/seed_visa_demo_account.py).\nNo auth required — this is for pre-signup \"show me the product\" visitors.\n\nIf the demo user isn't seeded yet the endpoint returns 404 so the\nfrontend can render a \"demo unavailable\" state instead of crashing.","operationId":"get_public_demo_scan_api_scans_demo_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResultResponse"}}}}}}},"/api/scans/helicone":{"post":{"tags":["scans"],"summary":"Submit Helicone Scan","description":"Runtime-informed scan: pull the caller's Helicone logs and project\nsavings from model-downgrade suggestions. Returns a completed scan\nsynchronously — no worker round-trip, no code upload, no tree-sitter.\n\nThis endpoint is how erabot plugs into existing runtime observability\ninstead of replacing it. A paying customer who already trusts Helicone's\ncost numbers gets a ranked fix list within ~10 seconds of pasting an API\nkey, correlated to their actual production traffic rather than\nhypothetical call patterns in source.","operationId":"submit_helicone_scan_api_scans_helicone_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_submit_helicone_scan_api_scans_helicone_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResultResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/langfuse":{"post":{"tags":["scans"],"summary":"Submit Langfuse Scan","description":"Runtime-informed scan from Langfuse observations. Mirror of /helicone.\n\nAccepts Langfuse public+secret key pair (HTTP Basic) and an optional\nhost for self-hosted deployments. Returns a completed scan synchronously.","operationId":"submit_langfuse_scan_api_scans_langfuse_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_submit_langfuse_scan_api_scans_langfuse_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResultResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/submit":{"post":{"tags":["scans"],"summary":"Submit Scan","description":"Submit a new scan job for background processing.\n\nAccepts paste (code in body), file (single-file upload, free tier),\nzip (multi-file upload), directory (path string), or github\n(repo_identifier) input sources.\n\nReturns immediately with job_id and status='queued'.\nPoll GET /scans/{job_id} for progress.\n\nFree tier: limited to 5 scans/month and 20 files/scan (returns 402 when\nexceeded). Paid tiers: unlimited scans.\n\nPhase 56 LAUNCH-39 (Plan 08): ``scans_paused`` kill switch is\nchecked FIRST so an on-call operator can stop scan ingestion in\n<30 seconds via the admin dashboard without a redeploy.","operationId":"submit_scan_api_scans_submit_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_submit_scan_api_scans_submit_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/try":{"post":{"tags":["scans"],"summary":"Try Scan","description":"Anonymous one-shot scan for the try-before-signup flow.\n\nNo ``access_token`` required. Accepts ``source=paste`` or\n``source=file`` only (the two free-tier sources). Uses a\n``try_session_id`` cookie + Redis counter to enforce a hard cap of\n1 scan per session. Rate-limited to 10 req/min/IP via slowapi so a\ndetermined attacker cannot mint thousands of sessions by spinning\nup fresh cookies (LAUNCH-13).\n\nOn the second attempt against the same session, returns HTTP 429\nwith ``{\"error\": \"sign_up_to_continue\", \"signup_url\": \"/signup\"}``.\n\nThe scan_job row is created with ``user_id=NULL`` and\n``try_session_id={cookie}``. On signup the\n``migrate_try_scans_to_user`` helper reassigns the row to the new\nuser's id (see auth.register).","operationId":"try_scan_api_scans_try_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_try_scan_api_scans_try_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/try/{job_id}":{"get":{"tags":["scans"],"summary":"Get Try Scan Status","description":"Poll status + pull savings for an anonymous try-scan.\n\nReturns the same shape as GET /{job_id} for authed users so the\nlanding-page widget can surface `total_monthly_savings_usd` inline\nbefore the signup gate.","operationId":"get_try_scan_status_api_scans_try__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResultResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/":{"get":{"tags":["scans"],"summary":"List Scans","description":"List scan history for the authenticated user (WSCAN-05, D-08).\n\nSupports sorting, pagination via limit/offset.","operationId":"list_scans_api_scans__get","parameters":[{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","pattern":"^(created_at|score|input_source|files_analyzed)$","default":"created_at","title":"Sort By"}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Sort Order"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanStatusResponse"},"title":"Response List Scans Api Scans  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{job_id}":{"get":{"tags":["scans"],"summary":"Get Scan Status","description":"Poll scan job status. Designed for sub-200ms response time (D-08).\n\nReturns current status and results (if complete).\nOnly the job owner can view their scan.","operationId":"get_scan_status_api_scans__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResultResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{job_id}/iterations":{"get":{"tags":["scans"],"summary":"Get Scan Iterations","description":"Return the helioscan iteration log for a scan job (D-11).\n\nReturns the full iteration_log array from the autoresearch_metadata\nJSON column (DB column kept for backward compat). Returns 404 if\nthe scan is not a helioscan scan or has no iteration data.\n\nDesigned for Phase 23 frontend timeline visualization.","operationId":"get_scan_iterations_api_scans__job_id__iterations_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{job_id}/report.md":{"get":{"tags":["scans"],"summary":"Download Report Md","description":"Download the markdown report for a completed scan (WSCAN-04, D-04).","operationId":"download_report_md_api_scans__job_id__report_md_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{job_id}/report.pdf":{"get":{"tags":["scans"],"summary":"Download Report Pdf","description":"Download the PDF report for a completed scan (WSCAN-04, D-04).","operationId":"download_report_pdf_api_scans__job_id__report_pdf_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{job_id}/report.patch":{"get":{"tags":["scans"],"summary":"Download Report Patch","description":"DEPRECATED (Phase 55). Returns HTTP 410 Gone.\n\nErabot no longer ships auto-generated difflib patches — that pipeline was\nproducing \"AI slop\" (hardcoded model-name overrides, incoherent grades,\netc.). The replacement artifact is `/scans/{job_id}/agent-instructions.md`,\nwhich is designed to be passed to a coding agent (e.g. `claude --file\nagent-instructions.md`) that has full repo context.\n\nThe route is intentionally kept registered so any external caller with a\nsaved `.patch` URL receives a clear 410 Gone migration pointer instead of\na confusing 404 Not Found. Auth is still enforced via `require_auth` so\nunauthenticated callers get 401 before seeing the 410 body.","operationId":"download_report_patch_api_scans__job_id__report_patch_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{job_id}/agent-instructions.md":{"get":{"tags":["scans"],"summary":"Download Agent Instructions","description":"Return the agent-instructions.md content for a completed scan as text/markdown.\n\nFor Phase 55+ scans, returns HTTP 200 with the rendered agent-instructions\nmarkdown populated by the worker (see worker.py + report_generator.py).\n\nFor pre-Phase-55 scans where `scan_job.agent_instructions` is NULL, returns\nHTTP 404 with a `migration_cutoff` body — the endpoint deliberately does\nNOT attempt to regenerate instructions on-the-fly from the old `code_after`\ndata. That code path is dead (Phase 55 root-causes the \"slop patches\" bug).","operationId":"download_agent_instructions_api_scans__job_id__agent_instructions_md_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Job Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{scan_id}/prior":{"get":{"tags":["scan_compare"],"summary":"Get Prior Scan","description":"LOOP-02: Auto-match the most recent PRIOR scan with matching repo_fingerprint.\n\nReturns 404 if no match exists -- frontend then offers LOOP-10 manual link button.","operationId":"get_prior_scan_api_scans__scan_id__prior_get","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scan Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PriorScanResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{scan_id}/compare/{other_id}":{"post":{"tags":["scan_compare"],"summary":"Compare Scans","description":"LOOP-02: Compute and persist a 3-bucket diff between two scans.\n\nIdempotent via unique constraint on (scan_a_id, scan_b_id). The compare\nendpoint always normalizes ordering (older scan becomes A) before insert.","operationId":"compare_scans_api_scans__scan_id__compare__other_id__post","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scan Id"}},{"name":"other_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Other Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanCompareResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{scan_id}/link/{other_id}":{"post":{"tags":["scan_compare"],"summary":"Link Scans","description":"LOOP-10: Manual 'Link to previous scan' fallback for cases where\nrepo_fingerprint auto-match fails (e.g., paste scans with different file sets).\n\nSame shape as /compare -- just bypasses the auto-match requirement.\nEmits a different PostHog event so we can measure how often users fall\nback to manual linking (signal for v5.1 improving path-only hashing).","operationId":"link_scans_api_scans__scan_id__link__other_id__post","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scan Id"}},{"name":"other_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Other Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanCompareResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scans/{scan_id}/rescan-config":{"get":{"tags":["scan_compare"],"summary":"Get Rescan Config","description":"LOOP-11: Return the inputs needed to pre-populate a re-scan form.\n\nFor GitHub scans: returns (source_type=github, repo_identifier).\nFor paste/upload scans: returns the sorted file_paths extracted from findings\n(best-effort -- does NOT contain the original code contents, so the frontend\nwill need to either re-upload or show a message).","operationId":"get_rescan_config_api_scans__scan_id__rescan_config_get","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scan Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RescanConfigResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/github/authorize":{"get":{"tags":["github-auth"],"summary":"Github Authorize","description":"Redirect the authenticated user to GitHub App authorization page.\n\nGenerates a random state token stored in Redis for CSRF protection.\nThe GitHub App permissions (contents:read) are configured on the App itself --\nwe do NOT pass scope= in the URL (this is a GitHub App flow, not OAuth App).","operationId":"github_authorize_auth_github_authorize_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/github/callback":{"get":{"tags":["github-auth"],"summary":"Github Callback","description":"Handle GitHub OAuth callback.\n\nNOTE: This endpoint does NOT require an auth cookie -- the GitHub redirect\nwon't carry it. Instead we authenticate the user either from:\n  (a) a JWT-signed state (Phase 58 D-08 install-url flow), OR\n  (b) a random Redis-backed state token (pre-Phase-58 /authorize flow).\n\nThe JWT path is detected by the presence of two dots in the state string\n(a JWT has exactly two \".\" separators: header.payload.signature). The\nrandom Redis state token (``secrets.token_urlsafe(32)``) has none.","operationId":"github_callback_auth_github_callback_get","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string","title":"Code"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}},{"name":"installation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Installation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/github/repos":{"get":{"tags":["github"],"summary":"List Repos","description":"List repos accessible to the user's GitHub installation (D-05).\n\nPyGithub is synchronous, so calls are wrapped in asyncio.to_thread().","operationId":"list_repos_api_github_repos_get","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string","default":"","title":"Search"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GitHubRepoResponse"},"title":"Response List Repos Api Github Repos Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/github/repos/{owner}/{repo}/branches":{"get":{"tags":["github"],"summary":"List Branches","description":"List branches for a specific repo (D-06).\n\nPyGithub is synchronous, so calls are wrapped in asyncio.to_thread().","operationId":"list_branches_api_github_repos__owner___repo__branches_get","parameters":[{"name":"owner","in":"path","required":true,"schema":{"type":"string","title":"Owner"}},{"name":"repo","in":"path","required":true,"schema":{"type":"string","title":"Repo"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GitHubBranchResponse"},"title":"Response List Branches Api Github Repos  Owner   Repo  Branches Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/github/status":{"get":{"tags":["github"],"summary":"Github Status","description":"Check whether the user has a connected GitHub installation.","operationId":"github_status_api_github_status_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitHubStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/github/pr/{scan_id}":{"post":{"tags":["github"],"summary":"Create Agent Instructions Pr Endpoint","description":"Create a ready-for-review PR committing ``agent-instructions.md`` to repo root.\n\nContract (D-02, D-14..D-19):\n  201 CreateGitHubPRSuccessResponse — new PR created\n  200 CreateGitHubPRSuccessResponse — idempotent: existing PR returned\n  402 {error: \"feature_required\", feature: \"github_integration\", upgrade_url: \"/pricing\"} (GH-11)\n  400 {error: \"paste_scans_not_supported_for_pr\"} when scan.input_source != \"github\" (GH-16)\n  409 {error: \"installation_required\", install_url} when no GitHubInstallation row\n  422 CreateGitHubPRSecretBlockedResponse when Wave 3 guard fires (GH-13, GH-14)\n  404 when scan doesn't exist or user doesn't own it","operationId":"create_agent_instructions_pr_endpoint_api_github_pr__scan_id__post","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scan Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/github/default-repo":{"get":{"tags":["github"],"summary":"Get Default Github Repo","description":"Return the current user's starred default repo (NULL = not set).","operationId":"get_default_github_repo_api_github_default_repo_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultGitHubRepoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["github"],"summary":"Set Default Github Repo","description":"Star (or unstar when repo is null) a default repo for one-click scanning.\n\nOne-starred-at-a-time semantics are enforced by overwriting the column.","operationId":"set_default_github_repo_api_github_default_repo_put","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultGitHubRepoRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultGitHubRepoResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/github/webhook":{"post":{"tags":["github"],"summary":"Github Webhook","description":"Inbound GitHub App webhook receiver.\n\nCurrently handles ``installation.deleted`` only (D-19). All other events\nare 200-no-op (GitHub marks the delivery successful and stops retrying).\n\nSecurity:\n  - HMAC-SHA256 verification of ``X-Hub-Signature-256`` using\n    ``settings.erabot_github_webhook_secret``. On failure → 401.\n  - An empty webhook secret rejects every request (verify_github_signature\n    returns False when secret is \"\"), preventing accidental open-door in\n    dev/staging with unconfigured apps.\n\nAtomicity:\n  - The three D-19 mutations (delete installation row, orphan active PR\n    records, flush token cache) run inside a single DB transaction. On any\n    exception before ``await db.commit()``, SQLAlchemy's async session\n    auto-rolls-back. The token-cache pop is a dict mutation on an\n    in-process singleton; it is called BEFORE the final commit, so on a\n    subsequent commit failure the cache is flushed but the row persists —\n    an acceptable inconsistency (the next token-use will refetch).","operationId":"github_webhook_api_github_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/github/install-url":{"get":{"tags":["github"],"summary":"Get Install Url","description":"Return a GitHub App install URL with a JWT-signed ``state`` parameter (D-08).\n\nClaims:\n  - ``purpose`` = ``\"github_install\"`` (cross-feature replay guard)\n  - ``user_id``\n  - ``scan_id`` (optional)\n  - ``redirect_to`` (optional, where the callback lands the user)\n  - ``iat`` / ``exp`` — 10-minute window\n\nThe frontend redirects the browser to the returned URL; GitHub redirects\nback to ``/auth/github/callback`` with ``state=<jwt>``, which is then\nverified by the JWT branch of that handler.","operationId":"get_install_url_api_github_install_url_get","parameters":[{"name":"scan_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Scan Id"}},{"name":"redirect_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redirect To"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout Session","description":"Create a Stripe Checkout session for a subscription tier upgrade.\n\nPer D-07: Stripe Checkout redirect flow.\nPer Pitfall 4: persist Stripe customer ID BEFORE creating checkout session.\nPer L1.4 (Plan 56-04): ``automatic_tax`` MANDATORY on every Checkout session\nfor UK VAT compliance.","operationId":"create_checkout_session_api_billing_checkout_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/portal":{"post":{"tags":["billing"],"summary":"Create Portal Session","description":"Create a Stripe Customer Portal session for subscription management.\n\nPer D-08 / LAUNCH-15: Stripe Customer Portal redirect.","operationId":"create_portal_session_api_billing_portal_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/tier":{"get":{"tags":["billing"],"summary":"Get User Tier","description":"Query current user tier, scan count, and scan limit.\n\nResets monthly counter if past scan_reset_date.","operationId":"get_user_tier_api_billing_tier_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TierResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/webhooks/stripe":{"post":{"tags":["billing"],"summary":"Stripe Webhook","description":"Handle Stripe webhook events (idempotent).\n\nNO auth required -- Stripe calls this directly.\n\nL1.1 (Plan 56-04): uses atomic UPSERT ``INSERT ... ON CONFLICT (event_id)\nDO NOTHING RETURNING id`` on the ``stripe_events`` table. If the RETURNING\nrow is empty, another worker already claimed the event; we exit silently\nwith status=\"duplicate\". This replaces the previous SELECT-then-INSERT\ntwo-step pattern which had a check-then-write race under concurrent\nwebhook delivery.\n\nPer Pitfall 1: read raw body before construct_event (never use request.json()).\nPer D-09: idempotent via stripe_events table dedup.","operationId":"stripe_webhook_api_billing_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}}}}},"/api/cicd/scan":{"post":{"tags":["cicd"],"summary":"Cicd Scan","description":"Accept a ZIP of repository files, run audit, return findings JSON.\n\nCalled by erabot/scan-action. Auth via Bearer token (erabot API key).\nReturns a ScanResult-shaped dict the Action consumes directly.","operationId":"cicd_scan_api_cicd_scan_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_cicd_scan_api_cicd_scan_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cicd Scan Api Cicd Scan Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/alerts/":{"post":{"tags":["alerts"],"summary":"Create Alert Rule","description":"Create a new alert rule for the authenticated user.","operationId":"create_alert_rule_api_alerts__post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["alerts"],"summary":"List Alert Rules","description":"List alert rules for the authenticated user.\n\nBy default returns only active rules. Pass ?include_inactive=true to include all.","operationId":"list_alert_rules_api_alerts__get","parameters":[{"name":"include_inactive","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Inactive"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"},"title":"Response List Alert Rules Api Alerts  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/alerts/{rule_id}":{"patch":{"tags":["alerts"],"summary":"Update Alert Rule","description":"Update an alert rule owned by the authenticated user.","operationId":"update_alert_rule_api_alerts__rule_id__patch","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["alerts"],"summary":"Delete Alert Rule","description":"Soft-delete an alert rule by setting is_active=False.","operationId":"delete_alert_rule_api_alerts__rule_id__delete","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Alert Rule Api Alerts  Rule Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/alerts/events":{"get":{"tags":["alerts"],"summary":"List Alert Events","description":"List the most recent alert events for all rules owned by the authenticated user.","operationId":"list_alert_events_api_alerts_events_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertEventResponse"},"title":"Response List Alert Events Api Alerts Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/my-org":{"get":{"tags":["teams"],"summary":"Get My Org","description":"Return the organization owned by the current user, or the first one they belong to.\n\nReturns null (204 body) if the user has no organization.","operationId":"get_my_org_api_teams_my_org_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/OrgResponse"},{"type":"null"}],"title":"Response Get My Org Api Teams My Org Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/orgs":{"post":{"tags":["teams"],"summary":"Create Org","description":"Create a new organization. The caller becomes the org owner.","operationId":"create_org_api_teams_orgs_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/orgs/{org_id}":{"get":{"tags":["teams"],"summary":"Get Org","description":"Return org details with team list. Only accessible by org members/owner.","operationId":"get_org_api_teams_orgs__org_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/orgs/{org_id}/teams":{"post":{"tags":["teams"],"summary":"Create Team","description":"Create a team within an org. Only org owner or admin.","operationId":"create_team_api_teams_orgs__org_id__teams_post","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/{team_id}":{"patch":{"tags":["teams"],"summary":"Update Team","description":"Update team name, budget_cap_usd, or fallback_model. Only org owner or admin.","operationId":"update_team_api_teams__team_id__patch","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Team Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/{team_id}/members":{"post":{"tags":["teams"],"summary":"Invite Member","description":"Invite a user (by email) to a team. Only org owner or admin.","operationId":"invite_member_api_teams__team_id__members_post","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Team Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberInvite"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/{team_id}/members/{member_user_id}":{"delete":{"tags":["teams"],"summary":"Remove Member","description":"Remove a member from a team. Only org owner or admin. Cannot remove last owner.","operationId":"remove_member_api_teams__team_id__members__member_user_id__delete","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Team Id"}},{"name":"member_user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Member User Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/teams/orgs/{org_id}/billing":{"get":{"tags":["teams"],"summary":"Get Org Billing","description":"Return total cost and per-team breakdown for a date range. Only org owner or admin.","operationId":"get_org_billing_api_teams_orgs__org_id__billing_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"period_start","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period Start"}},{"name":"period_end","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Period End"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgBillingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cache/metrics":{"get":{"tags":["cache-admin"],"summary":"Get Cache Metrics","description":"Get cache performance metrics for a project over a rolling window.\n\nReturns hit rate, total requests, cache hits, and estimated dollar savings.\nSavings are estimated by multiplying the number of cache hits per model by\nthe average cost per non-cached request for that model.","operationId":"get_cache_metrics_api_cache_metrics_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"default":30,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheMetrics"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cache/config":{"get":{"tags":["cache-admin"],"summary":"Get Cache Config","description":"Read per-project cache config from Redis. Returns module defaults if not set.","operationId":"get_cache_config_api_cache_config_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheConfigResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["cache-admin"],"summary":"Update Cache Config","description":"Persist per-project cache TTL and similarity threshold to Redis.\n\nValidation:\n- ttl_seconds: 60 <= x <= 86400\n- similarity_threshold: 0.7 <= x <= 1.0\nStored in Redis key ``semantic:config:{project_id}`` as JSON with no TTL\n(permanent config).","operationId":"update_cache_config_api_cache_config_patch","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheConfig"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheConfigResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/cache/warm-up":{"post":{"tags":["cache-admin"],"summary":"Warm Up Cache","description":"Pre-populate the semantic cache with known prompt/response pairs.\n\nProcesses entries in batches of 10 using asyncio.gather to bound concurrency.\nIndividual write failures are counted in ``entries_failed`` without aborting\nthe batch. Returns ``cache_unavailable`` status when Redis is not configured.","operationId":"warm_up_cache_api_cache_warm_up_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheWarmUpRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheWarmUpResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/recommendations/model-savings":{"get":{"tags":["recommendations"],"summary":"Get Model Savings","description":"Return model switch recommendations for a project.\n\nAggregates usage_records grouped by (model, task_type), computes current cost,\nlooks up cheaper alternatives, and returns rows where savings_pct >= 30%.","operationId":"get_model_savings_api_recommendations_model_savings_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"Project UUID to analyse","title":"Project Id"},"description":"Project UUID to analyse"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"minimum":1,"description":"Look-back window in days","default":30,"title":"Days"},"description":"Look-back window in days"},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelSavingsRecommendation"},"title":"Response Get Model Savings Api Recommendations Model Savings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/recommendations/apply-model":{"post":{"tags":["recommendations"],"summary":"Apply Model Override","description":"Store a model routing override in Redis.\n\nRedis key: model_override:{project_id}:{current_model} → recommended_model\nTTL: None (permanent until explicitly cleared).\n\nFails gracefully if Redis is unavailable — returns 200 with status \"applied_no_redis\".","operationId":"apply_model_override_api_recommendations_apply_model_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyModelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyModelResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/recommendations/applied-overrides":{"get":{"tags":["recommendations"],"summary":"Get Applied Overrides","description":"List all active model overrides for a project.\n\nReturns dict: {current_model: recommended_model, ...}\nReturns empty dict if Redis unavailable.","operationId":"get_applied_overrides_api_recommendations_applied_overrides_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","description":"Project UUID","title":"Project Id"},"description":"Project UUID"},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Applied Overrides Api Recommendations Applied Overrides Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/dashboard":{"get":{"tags":["enterprise"],"summary":"Get Dashboard","description":"Enterprise dashboard: org summary + team cards. Per D-02, D-03, D-09.","operationId":"get_dashboard_api_enterprise_dashboard_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterpriseDashboardResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/recommendations":{"get":{"tags":["enterprise"],"summary":"List Recommendations","description":"Paginated recommendations with filters. Per D-04, D-09.","operationId":"list_recommendations_api_enterprise_recommendations_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Page Size"}},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Severity"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"team_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Team Id"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","default":"created_at","title":"Sort By"}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","default":"desc","title":"Sort Order"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/recommendations/{rec_id}":{"patch":{"tags":["enterprise"],"summary":"Update Recommendation","description":"Update a recommendation's status. Per D-06, D-09.","operationId":"update_recommendation_api_enterprise_recommendations__rec_id__patch","parameters":[{"name":"rec_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rec Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationItem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/recommendations/bulk":{"post":{"tags":["enterprise"],"summary":"Bulk Update Recommendations","description":"Bulk update recommendation statuses. Per D-04, D-09.","operationId":"bulk_update_recommendations_api_enterprise_recommendations_bulk_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkRecommendationUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/analytics":{"get":{"tags":["enterprise"],"summary":"Get Enterprise Analytics","description":"Enterprise analytics: forecasting, anomaly detection, team comparison, ROI. Per D-11, D-12, D-14, D-09.","operationId":"get_enterprise_analytics_api_enterprise_analytics_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":90,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnterpriseAnalyticsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/repo-assignments":{"post":{"tags":["enterprise"],"summary":"Create Repo Assignment","description":"Assign a project/repo to a team. Requires admin role. Per D-08.","operationId":"create_repo_assignment_api_enterprise_repo_assignments_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepoAssignmentCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepoAssignmentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/repo-assignments/{assignment_id}":{"delete":{"tags":["enterprise"],"summary":"Delete Repo Assignment","description":"Remove a repo assignment. Requires admin role.","operationId":"delete_repo_assignment_api_enterprise_repo_assignments__assignment_id__delete","parameters":[{"name":"assignment_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Assignment Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/recommendations/resolution-trend":{"get":{"tags":["enterprise"],"summary":"Get Resolution Trend","description":"Resolution trend: daily recommendation counts by status. Per D-07, D-09.","operationId":"get_resolution_trend_api_enterprise_recommendations_resolution_trend_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":90,"title":"Days"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolutionTrend"},"title":"Response Get Resolution Trend Api Enterprise Recommendations Resolution Trend Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/export/csv":{"get":{"tags":["enterprise"],"summary":"Export Csv","description":"Export analytics data as CSV. Requires admin or owner role. Per D-13.","operationId":"export_csv_api_enterprise_export_csv_get","parameters":[{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date","title":"Start Date"}},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date","title":"End Date"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/enterprise/export/pdf":{"get":{"tags":["enterprise"],"summary":"Export Pdf","description":"Export enterprise report as PDF. Requires admin or owner role. Per D-13.","operationId":"export_pdf_api_enterprise_export_pdf_get","parameters":[{"name":"start_date","in":"query","required":true,"schema":{"type":"string","format":"date","title":"Start Date"}},{"name":"end_date","in":"query","required":true,"schema":{"type":"string","format":"date","title":"End Date"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/training/export":{"get":{"tags":["training"],"summary":"Export Training Data","description":"Export training data as JSONL formatted for Google's Gemini tuning API.\n\nSupports filtering by outcome and date range. Streams results to\nhandle large datasets without memory issues.\n\nQuery params:\n- format: Output format (currently only \"jsonl\")\n- outcome: Filter by outcome (\"kept\", \"discarded\", \"invalid\", \"error\")\n- since: ISO date string, filter created_at >= this date\n- limit: Max rows to export (default 10000, max 100000)","operationId":"export_training_data_api_training_export_get","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","pattern":"^(jsonl)$","default":"jsonl","title":"Format"}},{"name":"outcome","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(kept|discarded|invalid|error)$"},{"type":"null"}],"title":"Outcome"}},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"default":10000,"title":"Limit"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/training/stats":{"get":{"tags":["training"],"summary":"Get Training Stats","description":"Return summary statistics of collected training data.\n\nUseful for monitoring collection progress before fine-tuning.\nReturns total count, breakdown by outcome, and date range.","operationId":"get_training_stats_api_training_stats_get","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingStatsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/context/conversations":{"get":{"tags":["context"],"summary":"List Conversations","description":"List active conversation sessions for a project, sorted by last activity.\n\nReturns context utilization for each conversation.","operationId":"list_conversations_api_context_conversations_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/context/conversations/{conversation_id}":{"get":{"tags":["context"],"summary":"Get Conversation Context","description":"Get detailed context budget for a specific conversation.\n\nReturns token breakdown, utilization percentage, and remaining capacity.","operationId":"get_conversation_context_api_context_conversations__conversation_id__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","title":"Conversation Id"}},{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/context/summary":{"get":{"tags":["context"],"summary":"Get Context Summary","description":"Aggregate context stats across all conversations for a project.\n\nReturns total active conversations, average utilization, and top consumers.","operationId":"get_context_summary_api_context_summary_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Project Id"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/context/budget":{"post":{"tags":["context"],"summary":"Check Context Budget","description":"Check context budget for a messages array BEFORE sending.\n\nReturns token breakdown, utilization percentage, and whether optimization\nis needed. Does NOT forward to LLM — just analyzes the messages.\n\nThis is the SDK entry point: call this before sending to decide whether\nto apply sliding window, summarization, or proceed as-is.","operationId":"check_context_budget_api_context_budget_post","parameters":[{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextBudgetRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/newsletter/subscribe":{"post":{"tags":["newsletter"],"summary":"Subscribe","description":"Subscribe an email to newsletter updates.\n\nValidates email, checks for duplicates, rate-limits by IP.\nReturns success even for duplicate emails (no information leakage).","operationId":"subscribe_api_newsletter_subscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/optimize/{scan_id}":{"post":{"tags":["optimize"],"summary":"Create Optimization Pr","description":"DISABLED (Phase 55). Returns HTTP 503 Service Unavailable.\n\nThe Draft-PR endpoint from Phase 54 depended on Gemini-generated\nreplacement snippets that Phase 55 removed because they frequently\nproduced slop patches. This endpoint is temporarily disabled pending\nthe future Architect + Critic agent rework (strategic shift #1).\n\nCallers should use ``GET /scans/{id}/agent-instructions.md`` instead,\nwhich returns per-finding architectural context that a coding agent\ncan apply with full repo awareness.\n\nThe route decorator is preserved so that existing clients receive a\nclean 503 migration response rather than a 404.","operationId":"create_optimization_pr_api_optimize__scan_id__post","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scan Id"}},{"name":"finding_index","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Finding Index"}},{"name":"access_token","in":"cookie","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Access Token"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/feedback/applied":{"post":{"tags":["feedback"],"summary":"Applied Event","description":"LOOP-12: Accept a structured 'applied' event from an AI coding agent.\n\nVerifies HMAC-SHA256 signature against scan.telemetry_secret and enforces\na 24h freshness window. Returns 401 on any verification failure -- never\nleaks which check failed to prevent oracle attacks.","operationId":"applied_event_api_feedback_applied_post","parameters":[{"name":"X-Erabot-Signature","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Erabot-Signature"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppliedEventRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppliedEventResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Root","description":"Health check endpoint.","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health Check","description":"Detailed health check.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"APIKeyCreate":{"properties":{"name":{"type":"string","title":"Name"},"provider":{"type":"string","title":"Provider"},"provider_api_key":{"type":"string","title":"Provider Api Key"},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"}},"type":"object","required":["name","provider","provider_api_key"],"title":"APIKeyCreate"},"APIKeyResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"provider":{"type":"string","title":"Provider"},"erabot_key":{"type":"string","title":"Erabot Key"},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"}},"type":"object","required":["id","name","provider","erabot_key","is_active","created_at","last_used_at"],"title":"APIKeyResponse"},"AlertEventResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"rule_id":{"type":"string","format":"uuid","title":"Rule Id"},"triggered_at":{"type":"string","format":"date-time","title":"Triggered At"},"period_start":{"type":"string","format":"date-time","title":"Period Start"},"actual_spend_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Actual Spend Usd"},"threshold_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Threshold Usd"},"notified_webhook":{"type":"boolean","title":"Notified Webhook"},"notified_email":{"type":"boolean","title":"Notified Email"}},"type":"object","required":["id","rule_id","triggered_at","period_start","notified_webhook","notified_email"],"title":"AlertEventResponse","description":"Response schema for an alert event."},"AlertRuleCreate":{"properties":{"name":{"type":"string","title":"Name"},"scope_type":{"type":"string","pattern":"^(global|model|api_key|project)$","title":"Scope Type","default":"global"},"scope_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope Value"},"threshold_usd":{"type":"number","exclusiveMinimum":0.0,"title":"Threshold Usd"},"period":{"type":"string","pattern":"^(daily|monthly)$","title":"Period","default":"monthly"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"notify_email":{"type":"boolean","title":"Notify Email","default":true}},"type":"object","required":["name","threshold_usd"],"title":"AlertRuleCreate","description":"Request body for creating an alert rule."},"AlertRuleResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"name":{"type":"string","title":"Name"},"scope_type":{"type":"string","title":"Scope Type"},"scope_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope Value"},"threshold_usd":{"type":"number","title":"Threshold Usd"},"period":{"type":"string","title":"Period"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"notify_email":{"type":"boolean","title":"Notify Email"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","user_id","name","scope_type","threshold_usd","period","notify_email","is_active","created_at"],"title":"AlertRuleResponse","description":"Response schema for an alert rule."},"AlertRuleUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"scope_type":{"anyOf":[{"type":"string","pattern":"^(global|model|api_key|project)$"},{"type":"null"}],"title":"Scope Type"},"scope_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope Value"},"threshold_usd":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Threshold Usd"},"period":{"anyOf":[{"type":"string","pattern":"^(daily|monthly)$"},{"type":"null"}],"title":"Period"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"notify_email":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Email"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"type":"object","title":"AlertRuleUpdate","description":"Request body for updating an alert rule — all fields optional."},"AnomalyItem":{"properties":{"date":{"type":"string","title":"Date"},"cost_usd":{"type":"number","title":"Cost Usd"},"z_score":{"type":"number","title":"Z Score"},"rolling_mean":{"type":"number","title":"Rolling Mean"},"pct_deviation":{"type":"number","title":"Pct Deviation"},"direction":{"type":"string","title":"Direction"},"team_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Team Name"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"}},"type":"object","required":["date","cost_usd","z_score","rolling_mean","pct_deviation","direction"],"title":"AnomalyItem"},"AppliedEventRequest":{"properties":{"scan_id":{"type":"string","title":"Scan Id"},"finding_id":{"type":"string","title":"Finding Id"},"applied_at":{"type":"string","format":"date-time","title":"Applied At"},"tool_identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Identifier"},"diff_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Diff Hash"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["scan_id","finding_id","applied_at"],"title":"AppliedEventRequest","description":"Request body for POST /api/feedback/applied.\n\nAI coding agents post this when they finish applying a finding's fix.\nHMAC signature goes in X-Erabot-Signature header, computed over the\ncanonical string representation of this body (see feedback.py)."},"AppliedEventResponse":{"properties":{"status":{"type":"string","title":"Status","default":"accepted"},"event_id":{"type":"string","title":"Event Id"}},"type":"object","required":["event_id"],"title":"AppliedEventResponse"},"ApplyModelRequest":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"current_model":{"type":"string","title":"Current Model"},"recommended_model":{"type":"string","title":"Recommended Model"}},"type":"object","required":["project_id","current_model","recommended_model"],"title":"ApplyModelRequest","description":"Request to apply a model routing override."},"ApplyModelResponse":{"properties":{"status":{"type":"string","title":"Status"},"current_model":{"type":"string","title":"Current Model"},"recommended_model":{"type":"string","title":"Recommended Model"}},"type":"object","required":["status","current_model","recommended_model"],"title":"ApplyModelResponse","description":"Response after applying a model routing override."},"AuditFinding":{"properties":{"file_path":{"type":"string","title":"File Path"},"type":{"type":"string","title":"Type"},"description":{"type":"string","title":"Description"},"action":{"type":"string","title":"Action"},"priority":{"type":"string","title":"Priority"},"estimated_savings":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Estimated Savings"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"code_before":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Before"},"code_after":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code After"},"function_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Function Name"},"line_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Line Hint"},"auth_impact":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Auth Impact"},"score_delta":{"anyOf":[{"$ref":"#/components/schemas/ScoreDelta"},{"type":"null"}]}},"type":"object","required":["file_path","type","description","action","priority"],"title":"AuditFinding"},"AuditRequest":{"properties":{"path":{"type":"string","title":"Path"},"project_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Project Id"}},"type":"object","required":["path"],"title":"AuditRequest"},"AuditResponse":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"files_analyzed":{"type":"integer","title":"Files Analyzed"},"findings":{"items":{"$ref":"#/components/schemas/AuditFinding"},"type":"array","title":"Findings"},"score":{"type":"string","title":"Score"},"categorical_scores":{"additionalProperties":{"type":"integer"},"type":"object","title":"Categorical Scores"},"summary":{"type":"string","title":"Summary"}},"type":"object","required":["files_analyzed","findings","score","categorical_scores","summary"],"title":"AuditResponse"},"Body_cicd_scan_api_cicd_scan_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_cicd_scan_api_cicd_scan_post"},"Body_submit_helicone_scan_api_scans_helicone_post":{"properties":{"helicone_api_key":{"type":"string","title":"Helicone Api Key"},"window_days":{"type":"integer","maximum":90.0,"minimum":1.0,"title":"Window Days","default":30}},"type":"object","required":["helicone_api_key"],"title":"Body_submit_helicone_scan_api_scans_helicone_post"},"Body_submit_langfuse_scan_api_scans_langfuse_post":{"properties":{"langfuse_public_key":{"type":"string","title":"Langfuse Public Key"},"langfuse_secret_key":{"type":"string","title":"Langfuse Secret Key"},"langfuse_host":{"type":"string","title":"Langfuse Host","default":"https://cloud.langfuse.com"},"window_days":{"type":"integer","maximum":90.0,"minimum":1.0,"title":"Window Days","default":30}},"type":"object","required":["langfuse_public_key","langfuse_secret_key"],"title":"Body_submit_langfuse_scan_api_scans_langfuse_post"},"Body_submit_scan_api_scans_submit_post":{"properties":{"source":{"type":"string","pattern":"^(paste|file|zip|directory|github)$","title":"Source"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"repo_identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Identifier"},"scan_mode":{"type":"string","pattern":"^(standard|helioscan)$","title":"Scan Mode","default":"standard"},"calls_per_month":{"type":"integer","maximum":100000.0,"minimum":1.0,"title":"Calls Per Month","default":1000},"completion_ratio":{"type":"number","maximum":2.0,"minimum":0.1,"title":"Completion Ratio","default":0.5},"monthly_llm_spend_usd":{"type":"number","minimum":0.0,"title":"Monthly Llm Spend Usd","default":0.0}},"type":"object","required":["source"],"title":"Body_submit_scan_api_scans_submit_post"},"Body_try_scan_api_scans_try_post":{"properties":{"source":{"type":"string","pattern":"^(paste|file)$","title":"Source"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"scan_mode":{"type":"string","pattern":"^(standard|helioscan)$","title":"Scan Mode","default":"standard"},"calls_per_month":{"type":"integer","maximum":100000.0,"minimum":1.0,"title":"Calls Per Month","default":1000},"completion_ratio":{"type":"number","maximum":2.0,"minimum":0.1,"title":"Completion Ratio","default":0.5},"monthly_llm_spend_usd":{"type":"number","minimum":0.0,"title":"Monthly Llm Spend Usd","default":0.0}},"type":"object","required":["source"],"title":"Body_try_scan_api_scans_try_post"},"BulkRecommendationUpdateRequest":{"properties":{"ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Ids"},"status":{"type":"string","pattern":"^(fixed|dismissed)$","title":"Status"}},"type":"object","required":["ids","status"],"title":"BulkRecommendationUpdateRequest"},"CacheConfig":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"ttl_seconds":{"type":"integer","maximum":86400.0,"minimum":60.0,"title":"Ttl Seconds","default":3600},"similarity_threshold":{"type":"number","maximum":1.0,"minimum":0.7,"title":"Similarity Threshold","default":0.92}},"type":"object","required":["project_id"],"title":"CacheConfig"},"CacheConfigResponse":{"properties":{"ttl_seconds":{"type":"integer","title":"Ttl Seconds"},"similarity_threshold":{"type":"number","title":"Similarity Threshold"}},"type":"object","required":["ttl_seconds","similarity_threshold"],"title":"CacheConfigResponse"},"CacheMetrics":{"properties":{"hit_rate":{"type":"number","title":"Hit Rate"},"total_requests":{"type":"integer","title":"Total Requests"},"cache_hits":{"type":"integer","title":"Cache Hits"},"savings_usd":{"type":"number","title":"Savings Usd"},"savings_pct":{"type":"number","title":"Savings Pct"},"period_days":{"type":"integer","title":"Period Days"}},"type":"object","required":["hit_rate","total_requests","cache_hits","savings_usd","savings_pct","period_days"],"title":"CacheMetrics"},"CacheWarmUpEntry":{"properties":{"messages":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Messages"},"response":{"additionalProperties":true,"type":"object","title":"Response"}},"type":"object","required":["messages","response"],"title":"CacheWarmUpEntry"},"CacheWarmUpRequest":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"entries":{"items":{"$ref":"#/components/schemas/CacheWarmUpEntry"},"type":"array","maxItems":100,"title":"Entries","default":[]}},"type":"object","required":["project_id"],"title":"CacheWarmUpRequest"},"CacheWarmUpResponse":{"properties":{"status":{"type":"string","title":"Status"},"entries_written":{"type":"integer","title":"Entries Written"},"entries_failed":{"type":"integer","title":"Entries Failed"}},"type":"object","required":["status","entries_written","entries_failed"],"title":"CacheWarmUpResponse"},"ChatCompletionRequest":{"properties":{"model":{"type":"string","title":"Model"},"messages":{"items":{"$ref":"#/components/schemas/ChatMessage"},"type":"array","title":"Messages"},"temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Temperature","default":1.0},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"top_p":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top P","default":1.0},"frequency_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Frequency Penalty","default":0.0},"presence_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Presence Penalty","default":0.0},"stop":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Stop"},"stream":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Stream","default":false},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User"},"tw_cache_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Tw Cache Enabled","default":true},"tw_cache_ttl":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tw Cache Ttl","default":3600}},"type":"object","required":["model","messages"],"title":"ChatCompletionRequest"},"ChatMessage":{"properties":{"role":{"type":"string","title":"Role"},"content":{"type":"string","title":"Content"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","required":["role","content"],"title":"ChatMessage"},"CheckoutRequest":{"properties":{"tier":{"type":"string","pattern":"^(pro|team|enterprise)$","title":"Tier"}},"type":"object","required":["tier"],"title":"CheckoutRequest"},"CheckoutResponse":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"}},"type":"object","required":["checkout_url"],"title":"CheckoutResponse"},"ClientAnalytics":{"properties":{"client_id":{"type":"string","format":"uuid","title":"Client Id"},"total_cost_usd":{"type":"number","title":"Total Cost Usd"},"total_requests":{"type":"integer","title":"Total Requests"},"total_tokens":{"type":"integer","title":"Total Tokens"},"period_start":{"type":"string","format":"date-time","title":"Period Start"},"period_end":{"type":"string","format":"date-time","title":"Period End"}},"type":"object","required":["client_id","total_cost_usd","total_requests","total_tokens","period_start","period_end"],"title":"ClientAnalytics"},"ClientCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Budget Cap Usd"},"fallback_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fallback Model"},"monthly_billing_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Monthly Billing Usd"}},"type":"object","required":["name"],"title":"ClientCreate"},"ClientResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Cap Usd"},"is_archived":{"type":"boolean","title":"Is Archived"},"fallback_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fallback Model"},"monthly_billing_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Monthly Billing Usd"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","name","budget_cap_usd","is_archived","fallback_model","created_at"],"title":"ClientResponse"},"ClientUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Budget Cap Usd"},"fallback_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fallback Model"},"monthly_billing_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Monthly Billing Usd"}},"type":"object","title":"ClientUpdate"},"ClientWithMTD":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Cap Usd"},"is_archived":{"type":"boolean","title":"Is Archived"},"fallback_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fallback Model"},"monthly_billing_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Monthly Billing Usd"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"mtd_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mtd Cost"},"request_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Request Count"},"budget_utilization_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Utilization Pct"},"margin_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Margin Usd"},"is_profitable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Profitable"}},"type":"object","required":["id","name","budget_cap_usd","is_archived","fallback_model","created_at"],"title":"ClientWithMTD","description":"ClientResponse extended with MTD spend for ATTR-03 ranked list."},"ContextBudgetRequest":{"properties":{"model":{"type":"string","title":"Model"},"messages":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Messages"},"target_pct":{"type":"number","title":"Target Pct","default":0.8}},"type":"object","required":["model","messages"],"title":"ContextBudgetRequest","description":"Request body for pre-send context budget check."},"DefaultGitHubRepoRequest":{"properties":{"repo":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9_.\\-]+/[A-Za-z0-9_.\\-]+$"},{"type":"null"}],"title":"Repo"}},"type":"object","title":"DefaultGitHubRepoRequest","description":"PUT /api/github/default-repo body. Empty/null = unstar."},"DefaultGitHubRepoResponse":{"properties":{"repo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo"}},"type":"object","title":"DefaultGitHubRepoResponse","description":"GET/PUT /api/github/default-repo response body."},"EmbeddingRequest":{"properties":{"model":{"type":"string","title":"Model"},"input":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}],"title":"Input"},"encoding_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Encoding Format","default":"float"},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User"}},"type":"object","required":["model","input"],"title":"EmbeddingRequest"},"EnterpriseAnalyticsResponse":{"properties":{"forecast":{"items":{"$ref":"#/components/schemas/ForecastPoint"},"type":"array","title":"Forecast"},"anomalies":{"items":{"$ref":"#/components/schemas/AnomalyItem"},"type":"array","title":"Anomalies"},"team_comparisons":{"items":{"$ref":"#/components/schemas/TeamComparison"},"type":"array","title":"Team Comparisons"},"roi":{"items":{"$ref":"#/components/schemas/ROIItem"},"type":"array","title":"Roi"},"resolution_trend":{"items":{"$ref":"#/components/schemas/ResolutionTrend"},"type":"array","title":"Resolution Trend"}},"type":"object","required":["forecast","anomalies","team_comparisons","roi","resolution_trend"],"title":"EnterpriseAnalyticsResponse"},"EnterpriseDashboardResponse":{"properties":{"summary":{"$ref":"#/components/schemas/OrgSummary"},"teams":{"items":{"$ref":"#/components/schemas/TeamCard"},"type":"array","title":"Teams"}},"type":"object","required":["summary","teams"],"title":"EnterpriseDashboardResponse"},"ExecSummaryResponse":{"properties":{"current_month_cost_usd":{"type":"number","title":"Current Month Cost Usd"},"prev_month_cost_usd":{"type":"number","title":"Prev Month Cost Usd"},"projected_month_cost_usd":{"type":"number","title":"Projected Month Cost Usd"},"savings_captured_usd":{"type":"number","title":"Savings Captured Usd"},"savings_potential_usd":{"type":"number","title":"Savings Potential Usd"},"monthly_trend":{"items":{"$ref":"#/components/schemas/MonthlyTrendPoint"},"type":"array","title":"Monthly Trend"},"by_team":{"items":{"$ref":"#/components/schemas/TeamCostSummary"},"type":"array","title":"By Team"}},"type":"object","required":["current_month_cost_usd","prev_month_cost_usd","projected_month_cost_usd","savings_captured_usd","savings_potential_usd","monthly_trend","by_team"],"title":"ExecSummaryResponse"},"ForecastPoint":{"properties":{"date":{"type":"string","title":"Date"},"actual":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Actual"},"forecast":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Forecast"},"upper_band":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Upper Band"},"lower_band":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lower Band"}},"type":"object","required":["date"],"title":"ForecastPoint"},"ForgotPasswordRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"ForgotPasswordRequest"},"GitHubBranchResponse":{"properties":{"name":{"type":"string","title":"Name"},"protected":{"type":"boolean","title":"Protected"}},"type":"object","required":["name","protected"],"title":"GitHubBranchResponse"},"GitHubRepoResponse":{"properties":{"full_name":{"type":"string","title":"Full Name"},"name":{"type":"string","title":"Name"},"owner":{"type":"string","title":"Owner"},"private":{"type":"boolean","title":"Private"},"default_branch":{"type":"string","title":"Default Branch"}},"type":"object","required":["full_name","name","owner","private","default_branch"],"title":"GitHubRepoResponse"},"GitHubStatusResponse":{"properties":{"connected":{"type":"boolean","title":"Connected"},"installation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Installation Id"},"repos_count":{"type":"integer","title":"Repos Count","default":0}},"type":"object","required":["connected"],"title":"GitHubStatusResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"KnowledgeBaseStats":{"properties":{"total_chunks":{"type":"integer","title":"Total Chunks"},"sources":{"additionalProperties":true,"type":"object","title":"Sources"}},"type":"object","required":["total_chunks","sources"],"title":"KnowledgeBaseStats","description":"Statistics about the RAG knowledge base."},"LatencyEfficiency":{"properties":{"model":{"type":"string","title":"Model"},"avg_latency_ms":{"type":"number","title":"Avg Latency Ms"},"avg_cost_per_1k_tokens":{"type":"number","title":"Avg Cost Per 1K Tokens"}},"type":"object","required":["model","avg_latency_ms","avg_cost_per_1k_tokens"],"title":"LatencyEfficiency"},"LogBatch":{"properties":{"logs":{"items":{"$ref":"#/components/schemas/UsageLogEntry"},"type":"array","title":"Logs"}},"type":"object","required":["logs"],"title":"LogBatch","description":"Batch of logs from SDK."},"MemberInvite":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"MemberInvite"},"MemberResponse":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role"},"joined_at":{"type":"string","format":"date-time","title":"Joined At"}},"type":"object","required":["user_id","email","role","joined_at"],"title":"MemberResponse"},"ModelSavingsRecommendation":{"properties":{"current_model":{"type":"string","title":"Current Model"},"task_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Type"},"requests_last_30d":{"type":"integer","title":"Requests Last 30D"},"current_monthly_cost":{"type":"number","title":"Current Monthly Cost"},"recommended_model":{"type":"string","title":"Recommended Model"},"recommended_monthly_cost":{"type":"number","title":"Recommended Monthly Cost"},"savings_usd":{"type":"number","title":"Savings Usd"},"savings_pct":{"type":"number","title":"Savings Pct"},"quality_note":{"type":"string","title":"Quality Note"}},"type":"object","required":["current_model","requests_last_30d","current_monthly_cost","recommended_model","recommended_monthly_cost","savings_usd","savings_pct","quality_note"],"title":"ModelSavingsRecommendation","description":"Per-model recommendation with savings estimate."},"MonthlyTrendPoint":{"properties":{"month":{"type":"string","title":"Month"},"cost_usd":{"type":"number","title":"Cost Usd"}},"type":"object","required":["month","cost_usd"],"title":"MonthlyTrendPoint"},"OrgBillingResponse":{"properties":{"org_id":{"type":"string","format":"uuid","title":"Org Id"},"period_start":{"type":"string","format":"date-time","title":"Period Start"},"period_end":{"type":"string","format":"date-time","title":"Period End"},"total_cost_usd":{"type":"number","title":"Total Cost Usd"},"by_team":{"items":{"$ref":"#/components/schemas/TeamCostBreakdown"},"type":"array","title":"By Team","default":[]}},"type":"object","required":["org_id","period_start","period_end","total_cost_usd"],"title":"OrgBillingResponse"},"OrgCreate":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"OrgCreate"},"OrgResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"owner_id":{"type":"string","format":"uuid","title":"Owner Id"},"teams":{"items":{"$ref":"#/components/schemas/TeamSummary"},"type":"array","title":"Teams","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","name","owner_id","created_at"],"title":"OrgResponse"},"OrgSummary":{"properties":{"total_spend_usd":{"type":"number","title":"Total Spend Usd"},"total_savings_usd":{"type":"number","title":"Total Savings Usd"},"open_recommendations":{"type":"integer","title":"Open Recommendations"},"overall_health_score":{"type":"string","title":"Overall Health Score"},"team_count":{"type":"integer","title":"Team Count"},"repo_count":{"type":"integer","title":"Repo Count"}},"type":"object","required":["total_spend_usd","total_savings_usd","open_recommendations","overall_health_score","team_count","repo_count"],"title":"OrgSummary"},"PDFReportRequest":{"properties":{"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"type":"string","format":"date","title":"End Date"}},"type":"object","required":["start_date","end_date"],"title":"PDFReportRequest"},"PortalResponse":{"properties":{"portal_url":{"type":"string","title":"Portal Url"}},"type":"object","required":["portal_url"],"title":"PortalResponse"},"PriorScanResponse":{"properties":{"prior_scan_id":{"type":"string","title":"Prior Scan Id"},"prior_scan_created_at":{"type":"string","format":"date-time","title":"Prior Scan Created At"},"repo_fingerprint":{"type":"string","title":"Repo Fingerprint"}},"type":"object","required":["prior_scan_id","prior_scan_created_at","repo_fingerprint"],"title":"PriorScanResponse","description":"Response for GET /api/scans/{id}/prior -- auto-match by repo_fingerprint."},"ProjectBreakdown":{"properties":{"project_id":{"type":"string","format":"uuid","title":"Project Id"},"project_name":{"type":"string","title":"Project Name"},"total_cost_usd":{"type":"number","title":"Total Cost Usd"},"total_requests":{"type":"integer","title":"Total Requests"},"total_tokens":{"type":"integer","title":"Total Tokens"}},"type":"object","required":["project_id","project_name","total_cost_usd","total_requests","total_tokens"],"title":"ProjectBreakdown"},"ProjectComparison":{"properties":{"project_name":{"type":"string","title":"Project Name"},"total_cost":{"type":"number","title":"Total Cost"},"request_count":{"type":"number","title":"Request Count"},"savings_pct":{"type":"number","title":"Savings Pct"}},"type":"object","required":["project_name","total_cost","request_count","savings_pct"],"title":"ProjectComparison"},"ProjectCreate":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name"],"title":"ProjectCreate"},"ProjectResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"client_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Client Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","name","description","created_at"],"title":"ProjectResponse"},"PromptTemplateStats":{"properties":{"template_id":{"type":"string","format":"uuid","title":"Template Id"},"name":{"type":"string","title":"Name"},"total_calls":{"type":"integer","title":"Total Calls"},"total_cost_usd":{"type":"number","title":"Total Cost Usd"},"avg_tokens_per_call":{"type":"number","title":"Avg Tokens Per Call"},"avg_latency_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Latency Ms"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"}},"type":"object","required":["template_id","name","total_calls","total_cost_usd","avg_tokens_per_call","avg_latency_ms","last_used_at"],"title":"PromptTemplateStats"},"PromptTemplatesResponse":{"properties":{"templates":{"items":{"$ref":"#/components/schemas/PromptTemplateStats"},"type":"array","title":"Templates"},"total_cost_usd":{"type":"number","title":"Total Cost Usd"},"period_days":{"type":"integer","title":"Period Days"}},"type":"object","required":["templates","total_cost_usd","period_days"],"title":"PromptTemplatesResponse"},"QuickAdviceRequest":{"properties":{"query":{"type":"string","title":"Query","description":"Question about LLM cost optimization"},"code_snippet":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code Snippet","description":"Optional code to analyze"}},"type":"object","required":["query"],"title":"QuickAdviceRequest","description":"Request for quick optimization advice."},"QuickAdviceResponse":{"properties":{"advice":{"type":"string","title":"Advice"},"sources":{"additionalProperties":true,"type":"object","title":"Sources"}},"type":"object","required":["advice","sources"],"title":"QuickAdviceResponse","description":"Response with optimization advice and sources."},"ROIItem":{"properties":{"team_name":{"type":"string","title":"Team Name"},"before_cost_usd":{"type":"number","title":"Before Cost Usd"},"after_cost_usd":{"type":"number","title":"After Cost Usd"},"savings_usd":{"type":"number","title":"Savings Usd"},"recommendations_applied":{"type":"integer","title":"Recommendations Applied"}},"type":"object","required":["team_name","before_cost_usd","after_cost_usd","savings_usd","recommendations_applied"],"title":"ROIItem"},"RecommendationItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"severity":{"type":"string","title":"Severity"},"status":{"type":"string","title":"Status"},"team_name":{"type":"string","title":"Team Name"},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path"},"estimated_savings_usd":{"type":"number","title":"Estimated Savings Usd"},"finding_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finding Type"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"resolved_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved By"}},"type":"object","required":["id","title","severity","status","team_name","estimated_savings_usd","created_at"],"title":"RecommendationItem"},"RecommendationListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/RecommendationItem"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"page":{"type":"integer","title":"Page"},"page_size":{"type":"integer","title":"Page Size"},"open_count":{"type":"integer","title":"Open Count"},"fixed_count":{"type":"integer","title":"Fixed Count"},"dismissed_count":{"type":"integer","title":"Dismissed Count"},"verified_fixed_count":{"type":"integer","title":"Verified Fixed Count"}},"type":"object","required":["items","total","page","page_size","open_count","fixed_count","dismissed_count","verified_fixed_count"],"title":"RecommendationListResponse"},"RecommendationUpdateRequest":{"properties":{"status":{"type":"string","pattern":"^(fixed|dismissed|open)$","title":"Status"}},"type":"object","required":["status"],"title":"RecommendationUpdateRequest"},"RepoAssignmentCreate":{"properties":{"team_id":{"type":"string","format":"uuid","title":"Team Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"}},"type":"object","required":["team_id","project_id"],"title":"RepoAssignmentCreate"},"RepoAssignmentResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"team_id":{"type":"string","format":"uuid","title":"Team Id"},"project_id":{"type":"string","format":"uuid","title":"Project Id"},"assigned_at":{"type":"string","format":"date-time","title":"Assigned At"}},"type":"object","required":["id","team_id","project_id","assigned_at"],"title":"RepoAssignmentResponse"},"RescanConfigResponse":{"properties":{"source_type":{"type":"string","title":"Source Type"},"repo_identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Identifier"},"file_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"File Paths"}},"type":"object","required":["source_type"],"title":"RescanConfigResponse","description":"Response for GET /api/scans/{id}/rescan-config -- used by frontend to pre-populate re-scan form (LOOP-11)."},"ResetPasswordRequest":{"properties":{"token":{"type":"string","title":"Token"},"new_password":{"type":"string","maxLength":128,"minLength":8,"title":"New Password"}},"type":"object","required":["token","new_password"],"title":"ResetPasswordRequest"},"ResolutionTrend":{"properties":{"date":{"type":"string","title":"Date"},"open_count":{"type":"integer","title":"Open Count"},"fixed_count":{"type":"integer","title":"Fixed Count"},"dismissed_count":{"type":"integer","title":"Dismissed Count"},"verified_fixed_count":{"type":"integer","title":"Verified Fixed Count"}},"type":"object","required":["date","open_count","fixed_count","dismissed_count","verified_fixed_count"],"title":"ResolutionTrend"},"SavingsOverTime":{"properties":{"date":{"type":"string","format":"date-time","title":"Date"},"actual_cost":{"type":"number","title":"Actual Cost"},"potential_cost":{"type":"number","title":"Potential Cost"},"savings":{"type":"number","title":"Savings"}},"type":"object","required":["date","actual_cost","potential_cost","savings"],"title":"SavingsOverTime"},"ScanCompareBucketFinding":{"properties":{"file_path":{"type":"string","title":"File Path"},"type":{"type":"string","title":"Type"},"function_name":{"type":"string","title":"Function Name","default":""},"description":{"type":"string","title":"Description","default":""},"estimated_monthly_savings_usd":{"type":"number","title":"Estimated Monthly Savings Usd","default":0.0}},"type":"object","required":["file_path","type"],"title":"ScanCompareBucketFinding","description":"Slim finding shape for compare page -- only the fields the frontend needs."},"ScanCompareResponse":{"properties":{"scan_a_id":{"type":"string","title":"Scan A Id"},"scan_b_id":{"type":"string","title":"Scan B Id"},"findings_resolved":{"type":"integer","title":"Findings Resolved"},"findings_new":{"type":"integer","title":"Findings New"},"findings_unchanged":{"type":"integer","title":"Findings Unchanged"},"savings_materialized_usd":{"type":"number","title":"Savings Materialized Usd"},"removed":{"items":{"$ref":"#/components/schemas/ScanCompareBucketFinding"},"type":"array","title":"Removed"},"unchanged":{"items":{"$ref":"#/components/schemas/ScanCompareBucketFinding"},"type":"array","title":"Unchanged"},"added":{"items":{"$ref":"#/components/schemas/ScanCompareBucketFinding"},"type":"array","title":"Added"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["scan_a_id","scan_b_id","findings_resolved","findings_new","findings_unchanged","savings_materialized_usd","removed","unchanged","added","created_at"],"title":"ScanCompareResponse","description":"Response for POST /api/scans/{a}/compare/{b} and POST /api/scans/{a}/link/{b}."},"ScanResultResponse":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id"},"status":{"type":"string","title":"Status"},"input_source":{"type":"string","title":"Input Source"},"files_analyzed":{"type":"integer","title":"Files Analyzed","default":0},"files_in_input":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Files In Input"},"tier_file_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tier File Limit"},"score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Score"},"total_estimated_savings_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Estimated Savings Pct"},"finding_count":{"type":"integer","title":"Finding Count","default":0},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"findings":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Findings"},"report_md":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Report Md"},"report_pdf_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Report Pdf Path"},"report_patch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Report Patch","description":"[DEPRECATED: Phase 55. Populated only for pre-Phase-55 scans. Use agent_instructions instead.]"},"agent_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Instructions","description":"Phase 55+ agent-instructions.md content, or None for pre-Phase-55 scans."},"executive_summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Executive Summary"},"total_monthly_cost_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Monthly Cost Usd"},"total_monthly_savings_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Monthly Savings Usd"},"total_tokens_wasted_per_month":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Tokens Wasted Per Month"},"avg_context_utilization_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Context Utilization Pct"},"savings_pct_of_total_spend":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Savings Pct Of Total Spend"},"scan_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scan Mode"},"helioscan_metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Helioscan Metadata"},"total_verified_findings":{"type":"integer","title":"Total Verified Findings","default":0},"warnings":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Warnings"}},"type":"object","required":["job_id","status","input_source","created_at"],"title":"ScanResultResponse"},"ScanStatusResponse":{"properties":{"job_id":{"type":"string","format":"uuid","title":"Job Id"},"status":{"type":"string","title":"Status"},"input_source":{"type":"string","title":"Input Source"},"files_analyzed":{"type":"integer","title":"Files Analyzed","default":0},"files_in_input":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Files In Input"},"tier_file_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tier File Limit"},"score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Score"},"total_estimated_savings_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Estimated Savings Pct"},"finding_count":{"type":"integer","title":"Finding Count","default":0},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"}},"type":"object","required":["job_id","status","input_source","created_at"],"title":"ScanStatusResponse"},"ScoreDelta":{"properties":{"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"current":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Current"},"after_fix":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"After Fix"},"grade_change":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grade Change"}},"type":"object","title":"ScoreDelta"},"SubscribeRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"source":{"type":"string","title":"Source","default":"landing_page"}},"type":"object","required":["email"],"title":"SubscribeRequest"},"SubscribeResponse":{"properties":{"success":{"type":"boolean","title":"Success"},"message":{"type":"string","title":"Message"}},"type":"object","required":["success","message"],"title":"SubscribeResponse"},"TeamCard":{"properties":{"team_id":{"type":"string","format":"uuid","title":"Team Id"},"team_name":{"type":"string","title":"Team Name"},"health_score":{"type":"string","title":"Health Score"},"monthly_spend_usd":{"type":"number","title":"Monthly Spend Usd"},"open_recommendations":{"type":"integer","title":"Open Recommendations"},"last_scan_date":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Scan Date"},"spend_trend":{"items":{"type":"number"},"type":"array","title":"Spend Trend"}},"type":"object","required":["team_id","team_name","health_score","monthly_spend_usd","open_recommendations","spend_trend"],"title":"TeamCard"},"TeamComparison":{"properties":{"team_id":{"type":"string","format":"uuid","title":"Team Id"},"team_name":{"type":"string","title":"Team Name"},"total_spend_usd":{"type":"number","title":"Total Spend Usd"},"request_count":{"type":"integer","title":"Request Count"},"cost_per_request":{"type":"number","title":"Cost Per Request"},"recommendation_count":{"type":"integer","title":"Recommendation Count"}},"type":"object","required":["team_id","team_name","total_spend_usd","request_count","cost_per_request","recommendation_count"],"title":"TeamComparison"},"TeamCostBreakdown":{"properties":{"team_id":{"type":"string","format":"uuid","title":"Team Id"},"team_name":{"type":"string","title":"Team Name"},"cost_usd":{"type":"number","title":"Cost Usd"},"request_count":{"type":"integer","title":"Request Count"}},"type":"object","required":["team_id","team_name","cost_usd","request_count"],"title":"TeamCostBreakdown"},"TeamCostSummary":{"properties":{"team_id":{"type":"string","format":"uuid","title":"Team Id"},"team_name":{"type":"string","title":"Team Name"},"cost_usd":{"type":"number","title":"Cost Usd"},"request_count":{"type":"integer","title":"Request Count"},"budget_cap_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Cap Usd"},"budget_utilization_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Utilization Pct"}},"type":"object","required":["team_id","team_name","cost_usd","request_count","budget_cap_usd","budget_utilization_pct"],"title":"TeamCostSummary"},"TeamCreate":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Budget Cap Usd"},"fallback_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fallback Model"}},"type":"object","required":["name"],"title":"TeamCreate"},"TeamResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"org_id":{"type":"string","format":"uuid","title":"Org Id"},"name":{"type":"string","title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Cap Usd"},"fallback_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fallback Model"},"member_count":{"type":"integer","title":"Member Count","default":0}},"type":"object","required":["id","org_id","name"],"title":"TeamResponse"},"TeamSummary":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Budget Cap Usd"},"member_count":{"type":"integer","title":"Member Count","default":0}},"type":"object","required":["id","name"],"title":"TeamSummary"},"TeamUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Name"},"budget_cap_usd":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Budget Cap Usd"},"fallback_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fallback Model"}},"type":"object","title":"TeamUpdate"},"TierResponse":{"properties":{"tier":{"type":"string","title":"Tier"},"scan_count_this_month":{"type":"integer","title":"Scan Count This Month"},"scan_limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Scan Limit"},"has_subscription":{"type":"boolean","title":"Has Subscription"}},"type":"object","required":["tier","scan_count_this_month","has_subscription"],"title":"TierResponse"},"TokenDistribution":{"properties":{"model":{"type":"string","title":"Model"},"input_tokens":{"type":"integer","title":"Input Tokens"},"output_tokens":{"type":"integer","title":"Output Tokens"}},"type":"object","required":["model","input_tokens","output_tokens"],"title":"TokenDistribution"},"TrainingStatsResponse":{"properties":{"total_examples":{"type":"integer","title":"Total Examples"},"by_outcome":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Outcome"},"earliest":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Earliest"},"latest":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Latest"}},"type":"object","required":["total_examples","by_outcome"],"title":"TrainingStatsResponse","description":"Summary statistics of collected training data for fine-tuning."},"UsageLogEntry":{"properties":{"app_id":{"type":"string","title":"App Id"},"model":{"type":"string","title":"Model"},"prompt_tokens":{"type":"integer","title":"Prompt Tokens"},"completion_tokens":{"type":"integer","title":"Completion Tokens"},"total_tokens":{"type":"integer","title":"Total Tokens"},"cost_usd":{"type":"number","title":"Cost Usd"},"timestamp":{"type":"string","title":"Timestamp"},"function_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Function Name"},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path"},"prompt_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Hash"},"latency_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latency Ms"},"cached_tokens":{"type":"integer","title":"Cached Tokens","default":0},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id"},"tags":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Tags"}},"type":"object","required":["app_id","model","prompt_tokens","completion_tokens","total_tokens","cost_usd","timestamp"],"title":"UsageLogEntry","description":"Single usage log from SDK."},"UsageOverview":{"properties":{"total_cost_usd":{"type":"number","title":"Total Cost Usd"},"total_requests":{"type":"integer","title":"Total Requests"},"total_tokens":{"type":"integer","title":"Total Tokens"},"cache_hit_rate":{"type":"number","title":"Cache Hit Rate"},"estimated_savings_usd":{"type":"number","title":"Estimated Savings Usd"},"period_start":{"type":"string","format":"date-time","title":"Period Start"},"period_end":{"type":"string","format":"date-time","title":"Period End"}},"type":"object","required":["total_cost_usd","total_requests","total_tokens","cache_hit_rate","estimated_savings_usd","period_start","period_end"],"title":"UsageOverview"},"UserCreate":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","maxLength":128,"minLength":8,"title":"Password"},"company_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Name"}},"type":"object","required":["email","password"],"title":"UserCreate"},"UserResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"company_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Company Name"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"email_verified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Email Verified At"}},"type":"object","required":["id","email","company_name","created_at"],"title":"UserResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WebhookResponse":{"properties":{"status":{"type":"string","title":"Status"}},"type":"object","required":["status"],"title":"WebhookResponse"}}}}