{"openapi":"3.1.0","info":{"title":"ShareValue.ai API","description":"Intelligent stock analysis powered by 4-pillar scoring methodology","version":"2.0.0"},"paths":{"/api/v1/auth/login":{"post":{"tags":["auth"],"summary":"Login","description":"Admin login endpoint.\n\nOn success, sets the JWT in an HttpOnly cookie (``admin_token``) and\nalso returns it in the JSON body so non-browser tooling (curl,\nscripts) can keep using the Authorization: Bearer fallback.\n\nRate limited to 5 attempts per hour per IP to prevent brute force attacks.","operationId":"login_api_v1_auth_login_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Token"}}}}},"security":[{"HTTPBasic":[]}]}},"/api/v1/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"Clear the admin_token cookie. Idempotent; safe to call when not logged in.","operationId":"logout_api_v1_auth_logout_post","responses":{"204":{"description":"Successful Response"}}}},"/api/v1/users/me":{"get":{"tags":["users"],"summary":"Get Me","description":"Return the user's preferences. Lazy-creates a row with geo-IP seed if absent.","operationId":"get_me_api_v1_users_me_get","parameters":[{"name":"X-User-Country-Hint","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Country-Hint"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Me Api V1 Users Me Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["users"],"summary":"Patch Me","description":"Update the user's preferences. Upserts; null clears to Global.","operationId":"patch_me_api_v1_users_me_patch","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchPreferencesBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Patch Me Api V1 Users Me Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/legal/privacy":{"get":{"tags":["legal"],"summary":"Get Privacy Policy","description":"Get the Privacy Policy.\n\nReturns the full privacy policy in markdown format.","operationId":"get_privacy_policy_api_v1_legal_privacy_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/legal/terms":{"get":{"tags":["legal"],"summary":"Get Terms Of Service","description":"Get the Terms of Service.\n\nReturns the full terms of service in markdown format.","operationId":"get_terms_of_service_api_v1_legal_terms_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/legal/privacy/summary":{"get":{"tags":["legal"],"summary":"Get Privacy Summary","description":"Get a summary of the Privacy Policy.\n\nReturns key points in JSON format for display in the UI.","operationId":"get_privacy_summary_api_v1_legal_privacy_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/legal/terms/summary":{"get":{"tags":["legal"],"summary":"Get Terms Summary","description":"Get a summary of the Terms of Service.\n\nReturns key points in JSON format for display in the UI.","operationId":"get_terms_summary_api_v1_legal_terms_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/config/frontend":{"get":{"tags":["config"],"summary":"Get Frontend Config","description":"Get public configuration for frontend.\nNo authentication required - these are public keys.","operationId":"get_frontend_config_api_v1_config_frontend_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Frontend Config Api V1 Config Frontend Get"}}}}}}},"/api/v1/stocks/top":{"get":{"tags":["stocks"],"summary":"Get Top Stocks","description":"Get top-rated stocks sorted by specified pillar.\n\nSupports filtering by market cap tier, sector, and qualification status.\n\nArgs:\n    sort_by: Sort column (composite, valuation, quality, growth, health, final_score)\n    limit: Number of stocks to return (1-100)\n    tier: Market cap tier filter (mega, large, mid, small, micro)\n    sector: Sector filter (Technology, Healthcare, etc.)\n    include_unqualified: Include stocks that don't meet qualification criteria\n\nReturns:\n    List of stocks with scores, sorted by the specified pillar.","operationId":"get_top_stocks_api_v1_stocks_top_get","parameters":[{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Sort by: composite, valuation, quality, growth, health, final_score","default":"composite","title":"Sort By"},"description":"Sort by: composite, valuation, quality, growth, health, final_score"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Offset for pagination (lazy loading)","default":0,"title":"Offset"},"description":"Offset for pagination (lazy loading)"},{"name":"mode","in":"query","required":false,"schema":{"type":"string","pattern":"^(conservative|balanced|aggressive)$","description":"User mode: conservative, balanced, aggressive","default":"balanced","title":"Mode"},"description":"User mode: conservative, balanced, aggressive"},{"name":"tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Market cap tier: mega, large, mid, small, micro","title":"Tier"},"description":"Market cap tier: mega, large, mid, small, micro"},{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sector filter","title":"Sector"},"description":"Sector filter"},{"name":"include_unqualified","in":"query","required":false,"schema":{"type":"boolean","description":"Include unqualified stocks (low volume, etc.)","default":false,"title":"Include Unqualified"},"description":"Include unqualified stocks (low volume, etc.)"},{"name":"best_quality_only","in":"query","required":false,"schema":{"type":"boolean","description":"Only show Strong Buy/Buy + Low Risk stocks","default":false,"title":"Best Quality Only"},"description":"Only show Strong Buy/Buy + Low Risk stocks"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/leaderboard":{"get":{"tags":["stocks"],"summary":"Get Leaderboard","description":"Get leaderboard of top-performing stocks (ULTRA FAST).\n\nUses materialized view for blazing-fast queries (~60ms for 100 stocks).\nWhen include_unqualified=true, falls back to slower query (~500ms).\n\nFeatures:\n- Sorted by final score (composite + momentum overlay)\n- Optional sector filtering\n- Optional market cap tier filtering\n- Optional country filtering\n- Risk mode filtering (conservative filters out high-risk stocks)\n- Pagination support\n- Includes sector-specific metrics\n- Optional unqualified stocks (market_cap < $250M, price < $3, volume < 2M)\n\nPerformance: ~60ms qualified only, ~500ms with unqualified","operationId":"get_leaderboard_api_v1_stocks_leaderboard_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by sector","title":"Sector"},"description":"Filter by sector"},{"name":"market_cap_tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by market cap tier (Large, Mid, Small)","title":"Market Cap Tier"},"description":"Filter by market cap tier (Large, Mid, Small)"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country filter (US, CA, UK) or exchange code","title":"Country"},"description":"Country filter (US, CA, UK) or exchange code"},{"name":"mode","in":"query","required":false,"schema":{"type":"string","pattern":"^(conservative|balanced|aggressive)$","description":"Risk mode: conservative (low risk), balanced (all), aggressive (high risk)","default":"balanced","title":"Mode"},"description":"Risk mode: conservative (low risk), balanced (all), aggressive (high risk)"},{"name":"include_unqualified","in":"query","required":false,"schema":{"type":"boolean","description":"Include unqualified stocks (slower)","default":false,"title":"Include Unqualified"},"description":"Include unqualified stocks (slower)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Number of stocks to return","default":100,"title":"Limit"},"description":"Number of stocks to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset","default":0,"title":"Offset"},"description":"Pagination offset"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/homepage-top-picks":{"get":{"tags":["stocks"],"summary":"Get Homepage Top Picks","description":"Get top picks for homepage, sorted by return since discovery.\n\nUses pre-computed materialized view for ultra-fast queries (~5ms).\nReturns stocks with highest returns since first qualifying for the leaderboard.","operationId":"get_homepage_top_picks_api_v1_stocks_homepage_top_picks_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Number of stocks to return","default":20,"title":"Limit"},"description":"Number of stocks to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/sector-leaders":{"get":{"tags":["stocks"],"summary":"Get Sector Leaders","description":"Get top stocks for each sector.\n\nReturns the top-performing stocks grouped by sector, useful for:\n- Sector rotation strategies\n- Diversified portfolio construction\n- Sector comparison\n\nPerformance: ~100-200ms for all sectors","operationId":"get_sector_leaders_api_v1_stocks_sector_leaders_get","parameters":[{"name":"limit_per_sector","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Top N stocks per sector","default":10,"title":"Limit Per Sector"},"description":"Top N stocks per sector"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/{ticker}":{"get":{"tags":["stocks"],"summary":"Get Stock Analysis","description":"Get comprehensive stock analysis including scores, momentum, metrics, and signals.\n\nUses materialized view for fast queries (~60ms).\nIncludes sector-specific metrics (R&D, FFO, NIM, etc.)\n\nReturns complete analysis with:\n- Fundamental scores (valuation, quality, growth, health)\n- Momentum score and overlay\n- Buy/sell signal\n- Financial metrics\n- Verdicts\n- Sector-specific metrics","operationId":"get_stock_analysis_api_v1_stocks__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"as_of_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Date in YYYY-MM-DD format","title":"As Of Date"},"description":"Date in YYYY-MM-DD format"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/v2/{ticker}":{"get":{"tags":["stocks"],"summary":"Get Stock Analysis V2","description":"Get comprehensive stock analysis from materialized view (ULTRA FAST).\n\nThis endpoint uses the pre-computed materialized view for 10-50x faster response times.\n\nReturns complete analysis with:\n- All scores (composite, valuation, quality, growth, health, momentum, final)\n- Rankings and percentiles\n- All 54 standard metrics\n- Sector-specific metrics (R&D, FFO, AFFO, NIM)\n- AI-collected metrics\n- Calculated metrics (Price/FFO, yields)\n- Pre-calculated verdicts and signals\n- Price changes (1d, 1w, 1m)\n- Detailed momentum data\n\nPerformance: ~60ms (vs 500-1000ms for legacy endpoint)","operationId":"get_stock_analysis_v2_api_v1_stocks_v2__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/{ticker}/peers":{"get":{"tags":["stocks"],"summary":"Get Stock Peers","description":"Get industry peer comparison.\n\nReturns stocks in the same sub-industry with similar characteristics.","operationId":"get_stock_peers_api_v1_stocks__ticker__peers_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":5,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/{ticker}/metrics":{"get":{"tags":["stocks"],"summary":"Get Stock Metrics","description":"Get detailed metrics for a stock including sector-specific metrics.\n\nReturns comprehensive metrics breakdown:\n- Valuation metrics (PE, PB, PS, etc.)\n- Quality metrics (ROE, ROA, margins, etc.)\n- Growth metrics (revenue growth, earnings growth, etc.)\n- Health metrics (debt ratios, liquidity, etc.)\n- Sector-specific metrics (R&D, FFO, NIM, etc.)\n\nArgs:\n    ticker: Stock ticker symbol\n\nReturns:\n    Complete metrics breakdown with sector-specific data","operationId":"get_stock_metrics_api_v1_stocks__ticker__metrics_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/sector-averages/{sector}":{"get":{"tags":["stocks"],"summary":"Get Sector Averages","description":"Get average scores and metrics for a sector.\n\nUsed for comparison charts in research reports.","operationId":"get_sector_averages_api_v1_stocks_sector_averages__sector__get","parameters":[{"name":"sector","in":"path","required":true,"schema":{"type":"string","title":"Sector"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stocks/bulk/leaderboard":{"get":{"tags":["stocks"],"summary":"Get Bulk Leaderboard","description":"Bulk leaderboard endpoint for admin/sitemap use.\n\nRequires admin authentication.\nAllows fetching up to 10,000 stocks in a single request.\n\nUse cases:\n- Sitemap generation\n- Data exports\n- Admin dashboards\n\nSame filtering and sorting as regular leaderboard endpoint.","operationId":"get_bulk_leaderboard_api_v1_stocks_bulk_leaderboard_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by sector","title":"Sector"},"description":"Filter by sector"},{"name":"market_cap_tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by market cap tier (Large, Mid, Small)","title":"Market Cap Tier"},"description":"Filter by market cap tier (Large, Mid, Small)"},{"name":"mode","in":"query","required":false,"schema":{"type":"string","pattern":"^(conservative|balanced|aggressive)$","description":"Risk mode: conservative (low risk), balanced (all), aggressive (high risk)","default":"balanced","title":"Mode"},"description":"Risk mode: conservative (low risk), balanced (all), aggressive (high risk)"},{"name":"include_unqualified","in":"query","required":false,"schema":{"type":"boolean","description":"Include unqualified stocks (slower)","default":false,"title":"Include Unqualified"},"description":"Include unqualified stocks (slower)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"description":"Number of stocks to return (admin-only, max 10,000)","default":1000,"title":"Limit"},"description":"Number of stocks to return (admin-only, max 10,000)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset","default":0,"title":"Offset"},"description":"Pagination offset"},{"name":"x-bulk-token","in":"header","required":true,"schema":{"type":"string","title":"X-Bulk-Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ticker/{ticker}/peers":{"get":{"tags":["ticker-data"],"summary":"Get Ticker Peers","description":"Get smart peer comparison based on Industry & Market Cap.\nUsed for the 'Peers' sub-tab.","operationId":"get_ticker_peers_api_v1_ticker__ticker__peers_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":6,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ticker/{ticker}/dividends":{"get":{"tags":["ticker-data"],"summary":"Get Ticker Dividends","description":"Get dividend data including:\n- Summary metrics (yield, payout ratio, growth rate, etc.)\n- Annual history (from DB)\n- Last announced dividend details\n\nOptimized to use minimal queries with JOINs where possible.","operationId":"get_ticker_dividends_api_v1_ticker__ticker__dividends_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ticker/{ticker}/earnings":{"get":{"tags":["ticker-data"],"summary":"Get Ticker Earnings","description":"Get earnings data:\n- Surprise History (from DB earnings_history table)\n- Analyst Estimates (from DB analyst_data table)\n- Next Earnings Date (from DB earnings_history table - find next future date)","operationId":"get_ticker_earnings_api_v1_ticker__ticker__earnings_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ticker/{ticker}/vals":{"get":{"tags":["ticker-data"],"summary":"Get Ticker Valuations","description":"Get Sector Valuation comparisons.\nReturns the sector medians for comparison with this stock.","operationId":"get_ticker_valuations_api_v1_ticker__ticker__vals_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ticker/{ticker}/financials":{"get":{"tags":["ticker-data"],"summary":"Get Ticker Financials","description":"Get detailed financial statements data from database:\n- Income Statement (quarterly + annual with detailed line items)\n- Balance Sheet (quarterly + annual with detailed line items)\n- Cash Flow Statement (quarterly + annual with detailed line items)\n\nAnnual data is sourced from 'FY' (Full Year) records which come from 10-K filings.\nFor stocks without FY data, we aggregate quarters as a fallback.","operationId":"get_ticker_financials_api_v1_ticker__ticker__financials_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/search":{"get":{"tags":["search"],"summary":"Search Stocks","description":"Search for stocks by ticker symbol or company name.\n\nSupports both ticker and name matching with intelligent ranking:\n- Ticker exact match (highest priority)\n- Ticker prefix match\n- Company name starts with query\n- Company name contains query\n\nExamples:\n    - \"AP\" → Returns AP, APA, AAPL (Apple), AMAT (Applied Materials)\n    - \"apple\" → Returns AAPL (Apple Inc.)\n    - \"micro\" → Returns MSFT (Microsoft), MU (Micron Technology)\n    - \"applied materials\" → Returns AMAT (Applied Materials)\n\nUses stock_analysis_view materialized view (~5.5k stocks) with:\n- B-tree index for fast ticker prefix search\n- Trigram index for fast name fuzzy search\n\nPerformance: <100ms database query (95th percentile)\nSecurity: Input is validated and sanitized to prevent SQL injection.","operationId":"search_stocks_api_v1_search_get","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":50,"description":"Search query (ticker or company name)","title":"Q"},"description":"Search query (ticker or company name)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Search Stocks Api V1 Search Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/screener/presets":{"get":{"tags":["screener"],"summary":"Get Presets","description":"Get all available preset screens with result counts.\n\nOptimized to run all COUNT queries in a single SQL statement.","operationId":"get_presets_api_v1_screener_presets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/screener/filters/options":{"get":{"tags":["screener"],"summary":"Get Filter Options","description":"Get available filter options (sectors, industries) for dropdowns.","operationId":"get_filter_options_api_v1_screener_filters_options_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/screener/presets/{preset_id}":{"get":{"tags":["screener"],"summary":"Run Preset","description":"Run a preset screen and return results.\nSorting can be overridden via query parameters.","operationId":"run_preset_api_v1_screener_presets__preset_id__get","parameters":[{"name":"preset_id","in":"path","required":true,"schema":{"$ref":"#/components/schemas/PresetScreen"}},{"name":"sort_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Column to sort by (overrides preset default)","title":"Sort By"},"description":"Column to sort by (overrides preset default)"},{"name":"sort_order","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(asc|desc)$"},{"type":"null"}],"description":"Sort order (overrides preset default)","title":"Sort Order"},"description":"Sort order (overrides preset default)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/screener/screen":{"post":{"tags":["screener"],"summary":"Screen Stocks Post","description":"Screen stocks with custom filters (POST for complex filters).","operationId":"screen_stocks_post_api_v1_screener_screen_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/screener":{"get":{"tags":["screener"],"summary":"Screen Stocks Get","description":"Screen stocks with query parameters (GET for simple filters).","operationId":"screen_stocks_get_api_v1_screener_get","parameters":[{"name":"min_composite_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Composite Score"}},{"name":"max_composite_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Max Composite Score"}},{"name":"min_valuation_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Valuation Score"}},{"name":"min_quality_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Quality Score"}},{"name":"min_growth_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Growth Score"}},{"name":"min_health_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Health Score"}},{"name":"min_momentum_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Momentum Score"}},{"name":"min_pe_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pe Ratio"}},{"name":"max_pe_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pe Ratio"}},{"name":"min_pb_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pb Ratio"}},{"name":"max_pb_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pb Ratio"}},{"name":"min_ps_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Ps Ratio"}},{"name":"max_ps_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Ps Ratio"}},{"name":"min_peg_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Peg Ratio"}},{"name":"max_peg_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Peg Ratio"}},{"name":"min_ev_ebitda","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Ev Ebitda"}},{"name":"max_ev_ebitda","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Ev Ebitda"}},{"name":"min_ev_sales","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Ev Sales"}},{"name":"max_ev_sales","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Ev Sales"}},{"name":"min_forward_pe","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Forward Pe"}},{"name":"max_forward_pe","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Forward Pe"}},{"name":"min_price_fcf","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Fcf"}},{"name":"max_price_fcf","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Fcf"}},{"name":"min_roe","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Roe"}},{"name":"max_roe","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Roe"}},{"name":"min_roa","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Roa"}},{"name":"max_roa","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Roa"}},{"name":"min_roic","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Roic"}},{"name":"max_roic","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Roic"}},{"name":"min_gross_margin","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Gross Margin"}},{"name":"min_operating_margin","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Operating Margin"}},{"name":"min_net_margin","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Net Margin"}},{"name":"min_fcf_margin","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Fcf Margin"}},{"name":"min_piotroski_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Piotroski Score"}},{"name":"min_revenue_growth_1y","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Revenue Growth 1Y"}},{"name":"max_revenue_growth_1y","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Revenue Growth 1Y"}},{"name":"min_eps_growth_1y","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Eps Growth 1Y"}},{"name":"max_eps_growth_1y","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Eps Growth 1Y"}},{"name":"min_fcf_growth_1y","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Fcf Growth 1Y"}},{"name":"min_dividend_growth","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Dividend Growth"}},{"name":"min_dividend_yield","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Dividend Yield"}},{"name":"max_dividend_yield","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Dividend Yield"}},{"name":"min_payout_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Payout Ratio"}},{"name":"max_payout_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Payout Ratio"}},{"name":"min_years_of_dividends","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Years Of Dividends"}},{"name":"min_current_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Current Ratio"}},{"name":"max_current_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Current Ratio"}},{"name":"min_quick_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Quick Ratio"}},{"name":"max_debt_to_equity","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Debt To Equity"}},{"name":"max_debt_to_ebitda","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Debt To Ebitda"}},{"name":"min_interest_coverage","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Interest Coverage"}},{"name":"min_altman_z_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Altman Z Score"}},{"name":"min_price_change_1w","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Change 1W"}},{"name":"max_price_change_1w","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Change 1W"}},{"name":"min_price_change_1m","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Change 1M"}},{"name":"max_price_change_1m","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Change 1M"}},{"name":"min_price_change_1y","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Change 1Y"}},{"name":"max_price_change_1y","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Change 1Y"}},{"name":"min_pct_from_52w_high","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pct From 52W High"}},{"name":"max_pct_from_52w_high","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pct From 52W High"}},{"name":"min_pct_from_52w_low","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pct From 52W Low"}},{"name":"max_pct_from_52w_low","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pct From 52W Low"}},{"name":"max_volatility_60d","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Volatility 60D"}},{"name":"sectors","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of sectors","title":"Sectors"},"description":"Comma-separated list of sectors"},{"name":"industries","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of industries","title":"Industries"},"description":"Comma-separated list of industries"},{"name":"exchanges","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of exchange codes (US, TO, LSE, etc.)","title":"Exchanges"},"description":"Comma-separated list of exchange codes (US, TO, LSE, etc.)"},{"name":"min_market_cap","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Market Cap"}},{"name":"max_market_cap","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Market Cap"}},{"name":"market_cap_tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Cap Tier"}},{"name":"min_price","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price"}},{"name":"max_price","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price"}},{"name":"min_beta","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Beta"}},{"name":"max_beta","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Beta"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","default":"composite_score","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":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/screener/sectors":{"get":{"tags":["screener"],"summary":"Get Sectors","description":"Get list of available sectors with stock counts.","operationId":"get_sectors_api_v1_screener_sectors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/screener/industries":{"get":{"tags":["screener"],"summary":"Get Industries","description":"Get list of available industries, optionally filtered by sector.","operationId":"get_industries_api_v1_screener_industries_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sector"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/screener/nl":{"post":{"tags":["screener"],"summary":"Nl Screen","description":"Screen stocks using natural language query.\n\nTranslates NL query to ScreenerFilters via LLM, then executes\nusing the same build_where_clause pipeline as the manual screener.","operationId":"nl_screen_api_v1_screener_nl_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLScreenerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLScreenerResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/industries":{"get":{"tags":["industries"],"summary":"List Industries","description":"List all available industries with stock counts.","operationId":"list_industries_api_v1_industries_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response List Industries Api V1 Industries Get"}}}}}}},"/api/v1/industries/{industry}":{"get":{"tags":["industries"],"summary":"Get Industry Rankings","description":"Get stock rankings for a specific industry.","operationId":"get_industry_rankings_api_v1_industries__industry__get","parameters":[{"name":"industry","in":"path","required":true,"schema":{"type":"string","title":"Industry"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Industry Rankings Api V1 Industries  Industry  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/industries/{industry}/stats":{"get":{"tags":["industries"],"summary":"Get Industry Stats","description":"Get statistical overview for an industry.","operationId":"get_industry_stats_api_v1_industries__industry__stats_get","parameters":[{"name":"industry","in":"path","required":true,"schema":{"type":"string","title":"Industry"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Industry Stats Api V1 Industries  Industry  Stats Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/prices/snapshots":{"get":{"tags":["prices"],"summary":"Get Price Snapshots Batch","description":"Fan out to /snapshot for many tickers in parallel; reuses the\nper-ticker Redis cache + lock dedup so 100 concurrent users on the\nsame screener page = 20-50 unique EODHD calls regardless of how\nmany fan-outs land at once.","operationId":"get_price_snapshots_batch_api_v1_prices_snapshots_get","parameters":[{"name":"tickers","in":"query","required":true,"schema":{"type":"string","description":"Comma-separated tickers, max 50. Example: AAPL.US,MSFT.US,GOOGL.US","title":"Tickers"},"description":"Comma-separated tickers, max 50. Example: AAPL.US,MSFT.US,GOOGL.US"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/prices/{ticker}/snapshot":{"get":{"tags":["prices"],"summary":"Get Price Snapshot","description":"Get current price snapshot for a ticker from EODHD real-time API.\n\nReturns live price with 15-20 minute delay from EODHD.\nFalls back to database if API fails.","operationId":"get_price_snapshot_api_v1_prices__ticker__snapshot_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/prices/{ticker}":{"get":{"tags":["prices"],"summary":"Get Price History","description":"Get historical price data for a ticker.\n\nFor short timeframes (< 1 year) or period='d': Returns daily data from database.\nFor long timeframes (≥ 1 year) with period='w' or 'm': Fetches aggregated data from EODHD API.\n\nThis adaptive approach avoids the need to store 10+ years of daily data while\nmaintaining chart quality for long-term views.","operationId":"get_price_history_api_v1_prices__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","description":"Start date (YYYY-MM-DD)","title":"From"},"description":"Start date (YYYY-MM-DD)"},{"name":"to","in":"query","required":true,"schema":{"type":"string","description":"End date (YYYY-MM-DD)","title":"To"},"description":"End date (YYYY-MM-DD)"},{"name":"period","in":"query","required":false,"schema":{"type":"string","pattern":"^(d|w|m)$","description":"Data period: 'd' (daily), 'w' (weekly), 'm' (monthly)","default":"d","title":"Period"},"description":"Data period: 'd' (daily), 'w' (weekly), 'm' (monthly)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/health":{"get":{"tags":["admin"],"summary":"Admin Health Check","description":"System health check with detailed metrics.","operationId":"admin_health_check_api_v1_admin_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/jobs/{job_name}/run":{"post":{"tags":["admin"],"summary":"Trigger Job","description":"Manually trigger background jobs.\n\nAvailable jobs:\n- backfill_prices: Backfill historical price data for momentum calculations\n  - Optional param: months (int) - Number of months to backfill (default: 13)\n- backfill_financials: One-time backfill of dividend and detailed financial data for all tickers\n  - Optional param: limit (int) - Limit number of tickers for testing (e.g., 50)\n  - Duration: ~7-8 minutes for all tickers (rate-limited to 900 calls/min)\n  - Use when: Need to populate new dividend_history and detailed fundamentals columns\n- backfill_dividends: Backfill complete dividend history without 10-year limitation\n  - Optional param: years (int) - Number of years to backfill (default: 30, max available from EODHD)\n  - Duration: ~2-4 hours for all tickers (fetches complete historical dividend data)\n  - Use when: Need to fix Dividend Champions leaderboard with full historical data\n- momentum_scoring: Run momentum calculation and scoring only (skips price ingestion)\n  - Duration: ~8-10 minutes\n  - Use when: Prices already ingested, need to complete scoring\n- weekly_refresh: Full fundamentals refresh (EODHD-based, chunked processing)\n  - Optional param: start_chunk (int) - Resume from specific chunk (default: 1)\n  - Duration: ~2-4 hours for full refresh\n  - Use when: Need to update fundamentals data for all tickers\n- force_recalculate_metrics: Force full metrics and scores recalculation for ALL tickers\n  - Duration: ~2-3 hours for 5,000 tickers\n  - Use when: After major code changes that invalidate existing calculations\n  - No API calls: Reuses existing fundamentals data\n- daily_refresh_v2: Complete daily pipeline\n  - Duration: ~20-30 minutes\n  - Pipeline: universe → fundamentals → prices → momentum → bulk metrics → vectorized scoring → risk → views → thesis\n  - Optional param: force_scoring (bool) - Force full momentum recalculation\n  - Optional param: skip_weekend_check (bool) - Skip weekend guard (admin testing)\n- fundamentals_history_refresh: Tier 2 per-ticker fundamentals history refresh (SHA-210)\n  - Calls /fundamentals/<TICKER> for tickers with stale MAX(fundamentals.updated_at)\n  - Optional param: staleness_days (int, 1-365) - Override default 30-day cutoff\n  - Optional param: max_tickers (int, 1-30000) - Override default 3,000-ticker circuit breaker\n  - Optional param: exchange (str) - Filter to one EODHD exchange (e.g. \"HK\"); bypasses staleness gate\n  - Use when: Manually trigger the same path as the nightly 03:30 ET Beat task; small targeted reruns\n  - For larger backfills (>30k tickers), use scripts/ingestion/backfill_fundamentals_history.py instead\n- ingest_statements: Tier 2 financial statements ingestion (SHA-460)\n  - Calls /fundamentals/<TICKER> and persists balance_sheets / income_statements / cash_flow_statements\n  - Underlying task is incremental (`get_tickers_needing_ingestion`); only changed tickers by default\n  - Optional param: force_recalculate (bool) - Process ALL tickers (bypass incremental gate). Use for the one-shot backfill\n  - Optional param: max_tickers (int, 1-30000) - Override the 5,000-ticker default cap. Omit for full backfill\n  - Optional param: quarters (int, 1-40) - Number of historical quarters to ingest per ticker (default 16 = 4 years)\n  - Use when: Manually trigger the 04:00 ET Beat path; one-shot backfill of an empty `balance_sheets` table\n- seo_daily_pull: SHA-435 SEO/AEO orchestrator (GSC + Bing + AEO grid)\n  - Beat-scheduled: daily at 09:00 UTC. Each child writes its own JobRun row\n  - Use when: Smoke-testing Railway env vars (GOOGLE_APPLICATION_CREDENTIALS_JSON,\n    GSC_PROPERTY_URL, BING_WEBMASTER_API_KEY, BING_SITE_URL) without waiting\n    for cron\n- seo_weekly_digest: SHA-435 weekly Linear comment on SHA-423\n  - Beat-scheduled: Mondays at 14:00 UTC. Reads last 7 days of GSC/Bing/AEO\n    snapshots and posts a markdown digest as a Linear comment\n\nThis endpoint allows manual triggering for testing or ad-hoc updates.\nThe task is executed asynchronously by Celery workers.","operationId":"trigger_job_api_v1_admin_jobs__job_name__run_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_name","in":"path","required":true,"schema":{"type":"string","title":"Job Name"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/JobParams"},{"type":"null"}],"title":"Params"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/jobs/ingest-ticker":{"post":{"tags":["admin"],"summary":"Ingest Single Ticker","description":"Ingest a single ticker's data using EODHD API.\n\nThis endpoint fetches and ingests all data for a single ticker:\n- Fundamentals (detailed income statement, balance sheet, cash flow - 46 line items)\n- Security details (sector, industry, market cap)\n- Valuation ratios\n- Analyst data (ratings, estimates)\n- Institutional holdings\n- Earnings history\n- Dividend history\n- Recent prices (last 30 days)\n\nUseful for:\n- Adding missing tickers\n- Testing data pipeline\n- Quick updates for specific stocks\n- Backfilling detailed financial data","operationId":"ingest_single_ticker_api_v1_admin_jobs_ingest_ticker_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestTickerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/jobs/refresh-prices":{"post":{"tags":["admin"],"summary":"Refresh Ticker Prices","description":"Refresh historical prices for a single ticker.\n\nThis endpoint fetches fresh split-adjusted prices from EODHD and replaces\nall existing price data for the ticker. Useful for:\n- Fixing stocks with incorrect split-adjusted data (e.g., NFLX after 10:1 split)\n- Manual intervention after detecting split issues\n\nThe endpoint fetches 13 months of history to ensure momentum calculations work.","operationId":"refresh_ticker_prices_api_v1_admin_jobs_refresh_prices_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestTickerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/jobs/test-bulk-prices":{"post":{"tags":["admin"],"summary":"Test Bulk Prices","description":"Test the bulk EOD price ingestion (runs synchronously, ~30 seconds).\n\nFetches all ~45,000 US tickers in one bulk API call (100 API calls),\nfilters to qualified universe, and upserts to daily_prices.","operationId":"test_bulk_prices_api_v1_admin_jobs_test_bulk_prices_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/jobs/refresh-materialized-views":{"post":{"tags":["admin"],"summary":"Refresh Materialized Views","description":"Refresh all materialized views that power the leaderboards.\n\nThis endpoint refreshes:\n- stock_analysis_view (powers dividend leaderboard)\n- stock_52w_view (powers 52W highs/lows leaderboards)\n- homepage_top_picks (powers homepage)\n\nUse this after data corruption or failed daily refresh to fix leaderboard data.\n\nNote: Uses REFRESH MATERIALIZED VIEW CONCURRENTLY to avoid table locking.\nTypical refresh time: 1-2 minutes for all three views.","operationId":"refresh_materialized_views_api_v1_admin_jobs_refresh_materialized_views_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/jobs/recalculate-dividend-quality":{"post":{"tags":["admin"],"summary":"Recalculate Dividend Quality","description":"Recalculate dividend quality scores for all dividend-paying stocks.\n\nThis endpoint:\n- Identifies all dividend-paying stocks from dividend_history table\n- Calculates comprehensive dividend quality scores (0-100)\n- Assigns letter grades (A+ to F) and designations (King, Aristocrat)\n- Updates stock_metrics with years_of_dividends and dividend_growth\n\nUse this after:\n- Dividend backfill completion\n- Bug fixes to dividend quality calculation\n- Missing or incorrect dividend data in leaderboards\n\nDuration: ~2-3 minutes for 2,000-3,000 dividend-paying stocks","operationId":"recalculate_dividend_quality_api_v1_admin_jobs_recalculate_dividend_quality_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/jobs/recalculate-ticker":{"post":{"tags":["admin"],"summary":"Recalculate Ticker","description":"Recalculate metrics, momentum, and scores for a single ticker.\n\nThis endpoint:\n1. Recalculates all metrics from existing fundamentals data\n2. Recalculates momentum scores from price data (uses adjusted_close for splits)\n3. Recalculates PILAR scores using the new metrics\n4. Refreshes the materialized view\n\nUseful for applying metric calculation fixes or fixing split-adjusted data.","operationId":"recalculate_ticker_api_v1_admin_jobs_recalculate_ticker_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestTickerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/data-quality":{"get":{"tags":["admin"],"summary":"Get Data Quality","description":"Get data quality metrics and validation results.","operationId":"get_data_quality_api_v1_admin_data_quality_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/api-keys":{"get":{"tags":["admin"],"summary":"List Api Keys","description":"List configured API keys (masked).\nReturns actual keys for admin to populate the UI.","operationId":"list_api_keys_api_v1_admin_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/api-keys/{service}":{"put":{"tags":["admin"],"summary":"Update Api Key","description":"Update API key for a service.\nNote: This endpoint accepts the key in the request body.","operationId":"update_api_key_api_v1_admin_api_keys__service__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"service","in":"path","required":true,"schema":{"type":"string","title":"Service"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/analytics":{"get":{"tags":["admin"],"summary":"Get Analytics","description":"Get usage analytics.","operationId":"get_analytics_api_v1_admin_analytics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/database/status":{"get":{"tags":["admin"],"summary":"Get Database Status","description":"Get database table row counts and status.","operationId":"get_database_status_api_v1_admin_database_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/migrations/run":{"post":{"tags":["admin"],"summary":"Run Migrations","description":"Create all database tables using SQLAlchemy models.\n\nThis is safer than Alembic migrations for initial setup.","operationId":"run_migrations_api_v1_admin_migrations_run_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/leaderboard-diagnostic":{"get":{"tags":["admin"],"summary":"Leaderboard Diagnostic","description":"Diagnostic endpoint to check why leaderboard might be empty.\n\nChecks:\n- stock_scores table\n- universe_tickers table\n- ticker_details table\n- Latest snapshot","operationId":"leaderboard_diagnostic_api_v1_admin_leaderboard_diagnostic_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/price-data-diagnostic":{"get":{"tags":["admin"],"summary":"Price Data Diagnostic","description":"Diagnostic endpoint to check price data availability for momentum calculations.\n\nReturns detailed information about:\n- daily_prices table (historical data for momentum)\n- universe_tickers prices (current prices only)\n- Date ranges and coverage","operationId":"price_data_diagnostic_api_v1_admin_price_data_diagnostic_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/bubble-watch/ingest-fred":{"post":{"tags":["admin"],"summary":"Ingest Fred Data","description":"Ingest FRED data (VIX, yield curve, interest rates).\n\nThis fetches the last year of data for all bubble watch series.\nRun this once initially, then it will update daily.","operationId":"ingest_fred_data_api_v1_admin_bubble_watch_ingest_fred_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/bubble-watch/ingest-macro":{"post":{"tags":["admin"],"summary":"Ingest Macro Data","description":"Ingest EODHD macro data (GDP, inflation, interest rates).\n\nThis fetches historical macro indicators for the USA.","operationId":"ingest_macro_data_api_v1_admin_bubble_watch_ingest_macro_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/bubble-watch/calculate":{"post":{"tags":["admin"],"summary":"Calculate Bubble Indicators","description":"Calculate bubble indicators for today.\n\nThis calculates:\n- Market valuations (P/E, P/B, Buffett Indicator)\n- Market breadth (% above MA, highs/lows)\n- Sector valuations\n- Composite bubble score","operationId":"calculate_bubble_indicators_api_v1_admin_bubble_watch_calculate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/bubble-watch/full-refresh":{"post":{"tags":["admin"],"summary":"Full Bubble Watch Refresh","description":"Run full bubble watch refresh: ingest all data sources and calculate.\n\nThis runs:\n1. FRED data ingestion (VIX, yield curve, Treasury yields, inflation)\n2. EODHD macro data ingestion (GDP, inflation)\n2b. S&P 500 historical data (30 years)\n2c. Economic calendar events\n3. Bubble indicator calculation\n4. Refresh materialized views\n\nUse this for initial setup or manual refresh.","operationId":"full_bubble_watch_refresh_api_v1_admin_bubble_watch_full_refresh_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/scheduled-tasks":{"get":{"tags":["admin"],"summary":"Get Scheduled Tasks","description":"List all scheduled task configurations with their enabled/disabled state.","operationId":"get_scheduled_tasks_api_v1_admin_scheduled_tasks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/scheduled-tasks/{task_key}":{"put":{"tags":["admin"],"summary":"Toggle Scheduled Task","description":"Toggle a scheduled task on or off.\n\nBody: { \"enabled\": true/false }","operationId":"toggle_scheduled_task_api_v1_admin_scheduled_tasks__task_key__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"task_key","in":"path","required":true,"schema":{"type":"string","title":"Task Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/popular-stocks":{"get":{"tags":["analytics"],"summary":"Get Popular Stocks","description":"Get most popular stocks by views.\n\nAdmin only endpoint.","operationId":"get_popular_stocks_api_v1_analytics_popular_stocks_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","pattern":"^(day|week|month)$","default":"week","title":"Period"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/popular-searches":{"get":{"tags":["analytics"],"summary":"Get Popular Searches","description":"Get most popular search queries.\n\nAdmin only endpoint.","operationId":"get_popular_searches_api_v1_analytics_popular_searches_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","pattern":"^(day|week|month)$","default":"week","title":"Period"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/user-modes":{"get":{"tags":["analytics"],"summary":"Get User Mode Distribution","description":"Get distribution of user modes (conservative/balanced/aggressive).\n\nAdmin only endpoint.","operationId":"get_user_mode_distribution_api_v1_analytics_user_modes_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","pattern":"^(day|week|month)$","default":"week","title":"Period"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analytics/performance":{"get":{"tags":["analytics"],"summary":"Get Performance Metrics","description":"Get API performance metrics.\n\nAdmin only endpoint.","operationId":"get_performance_metrics_api_v1_analytics_performance_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","pattern":"^(day|week|month)$","default":"week","title":"Period"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/jobs/{job_id}":{"get":{"tags":["jobs"],"summary":"Get Job Status","description":"Get status of a specific job.\n\nReturns real-time progress, status, and results.","operationId":"get_job_status_api_v1_admin_jobs__job_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Job Status Api V1 Admin Jobs  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/jobs":{"get":{"tags":["jobs"],"summary":"List Jobs","description":"List recent jobs with optional filtering.\n\nArgs:\n    job_name: Filter by job name (universe_build, data_ingestion, etc.)\n    status: Filter by status (pending, running, completed, failed)\n    limit: Maximum number of jobs to return","operationId":"list_jobs_api_v1_admin_jobs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by job name","title":"Job Name"},"description":"Filter by job name"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status","title":"Status"},"description":"Filter by status"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of jobs to return","default":20,"title":"Limit"},"description":"Number of jobs to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response List Jobs Api V1 Admin Jobs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/jobs/{job_id}/logs":{"get":{"tags":["jobs"],"summary":"Get Job Logs","description":"Get logs for a specific job (if available).\n\nNote: Currently returns basic info. Full log streaming\nwould require additional infrastructure (e.g., log aggregation).","operationId":"get_job_logs_api_v1_admin_jobs__job_id__logs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Job Logs Api V1 Admin Jobs  Job Id  Logs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/jobs/{job_id}/cancel":{"post":{"tags":["jobs"],"summary":"Cancel Job","description":"Cancel a running or pending job.\n\nRevokes the Celery task and updates the job status.","operationId":"cancel_job_api_v1_admin_jobs__job_id__cancel_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Cancel Job Api V1 Admin Jobs  Job Id  Cancel Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/thesis-generation/run":{"post":{"tags":["jobs"],"summary":"Run Thesis Generation","description":"Manually trigger AI thesis bullet generation.\n\nGenerates bullet points for stocks that don't have them or have expired ones.\nPrioritizes by market cap (larger companies first).\n\nArgs:\n    batch_size: Number of stocks to process (1-2000, default 100)\n\nReturns:\n    Job ID for tracking progress","operationId":"run_thesis_generation_api_v1_admin_thesis_generation_run_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"batch_size","in":"query","required":false,"schema":{"type":"integer","maximum":2000,"minimum":1,"description":"Number of stocks to generate thesis for","default":100,"title":"Batch Size"},"description":"Number of stocks to generate thesis for"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Run Thesis Generation Api V1 Admin Thesis Generation Run Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/thesis-generation/stats":{"get":{"tags":["jobs"],"summary":"Get Thesis Coverage Stats","description":"Get current AI thesis coverage statistics.\n\nReturns:\n    Coverage stats including total stocks, with/without bullets, coverage percentage","operationId":"get_thesis_coverage_stats_api_v1_admin_thesis_generation_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Thesis Coverage Stats Api V1 Admin Thesis Generation Stats Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/sentry/sentry/envelope":{"post":{"tags":["monitoring"],"summary":"Proxy Sentry Envelope","description":"Proxy Sentry envelope requests to hide DSN from frontend.\n\nFrontend sends events to this endpoint instead of directly to Sentry.\nThis prevents exposing the Sentry DSN in client-side code.","operationId":"proxy_sentry_envelope_api_v1_sentry_sentry_envelope_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/sentry/sentry/config":{"get":{"tags":["monitoring"],"summary":"Get Sentry Config","description":"Return Sentry configuration for frontend without exposing DSN.\n\nFrontend uses this to configure Sentry SDK to send events to our proxy.","operationId":"get_sentry_config_api_v1_sentry_sentry_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Sentry Config Api V1 Sentry Sentry Config Get"}}}}}}},"/api/v1/news/feed":{"get":{"tags":["news"],"summary":"Get News Feed","description":"Get general market news by topic tag for homepage feed widget.\n\nUses Redis caching (15-min TTL) since all users share the same feed per tag.\nCost: 5 API credits per cache miss.","operationId":"get_news_feed_api_v1_news_feed_get","parameters":[{"name":"tag","in":"query","required":false,"schema":{"type":"string","description":"Topic tag (e.g., USA, UK, INDIA, finance)","default":"USA","title":"Tag"},"description":"Topic tag (e.g., USA, UK, INDIA, finance)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":15,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get News Feed Api V1 News Feed Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news/{ticker}":{"get":{"tags":["news"],"summary":"Get Stock News","description":"Get news articles for a stock.\n\nUses database caching to minimize API calls.\n\n- **ticker**: Stock ticker symbol (e.g., AAPL)\n- **limit**: Number of articles to return (max 50)\n- **force_refresh**: Bypass cache and fetch fresh data from API\n\n**Caching**: Results cached for 1 hour\n**Cost**:\n- Cache hit: 0 API calls\n- Cache miss: 5 API calls","operationId":"get_stock_news_api_v1_news__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"default":10,"title":"Limit"}},{"name":"force_refresh","in":"query","required":false,"schema":{"type":"boolean","description":"Bypass cache and fetch fresh data","default":false,"title":"Force Refresh"},"description":"Bypass cache and fetch fresh data"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get Stock News Api V1 News  Ticker  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/sentiment/{ticker}":{"get":{"tags":["news"],"summary":"Get Stock Sentiment","description":"Get sentiment data for a stock.\n\nUses database caching to minimize API calls.\n\n- **ticker**: Stock ticker symbol (e.g., AAPL)\n- **days**: Number of days of historical data (max 365)\n- **force_refresh**: Bypass cache and fetch fresh data from API\n\n**Caching**: Results cached for 24 hours\n**Cost**:\n- Cache hit: 0 API calls\n- Cache miss: 5 API calls","operationId":"get_stock_sentiment_api_v1_sentiment__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":365,"default":30,"title":"Days"}},{"name":"force_refresh","in":"query","required":false,"schema":{"type":"boolean","description":"Bypass cache and fetch fresh data","default":false,"title":"Force Refresh"},"description":"Bypass cache and fetch fresh data"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Stock Sentiment Api V1 Sentiment  Ticker  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/cache/stats":{"get":{"tags":["news"],"summary":"Get Cache Stats","description":"Get news cache statistics for monitoring.\n\nReturns:\n- Total cached entries\n- Fresh vs stale counts\n- TTL configuration","operationId":"get_cache_stats_api_v1_cache_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Cache Stats Api V1 Cache Stats Get"}}}}}}},"/api/v1/cache/{ticker}":{"delete":{"tags":["news"],"summary":"Invalidate Cache","description":"Invalidate cache for a specific ticker.\n\nUseful for forcing a refresh of stale data.\n\n- **ticker**: Stock ticker symbol\n- **news**: If true, invalidate news cache\n- **sentiment**: If true, invalidate sentiment cache","operationId":"invalidate_cache_api_v1_cache__ticker__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"news","in":"query","required":false,"schema":{"type":"boolean","description":"Invalidate news cache","default":true,"title":"News"},"description":"Invalidate news cache"},{"name":"sentiment","in":"query","required":false,"schema":{"type":"boolean","description":"Invalidate sentiment cache","default":true,"title":"Sentiment"},"description":"Invalidate sentiment cache"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Invalidate Cache Api V1 Cache  Ticker  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/thesis/{ticker}/status":{"get":{"tags":["thesis","thesis"],"summary":"Get Thesis Status","description":"Get the current status of thesis for a ticker.","operationId":"get_thesis_status_api_v1_thesis__ticker__status_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/thesis/{ticker}/bullets":{"get":{"tags":["thesis","thesis"],"summary":"Get Bullet Points","description":"Get 5 bullet point investment summary.\n\nUses sonar model for fast generation.\nCached for 30 days.","operationId":"get_bullet_points_api_v1_thesis__ticker__bullets_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"force_refresh","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force Refresh"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/thesis/{ticker}/bullets/stream":{"get":{"tags":["thesis","thesis"],"summary":"Stream Bullet Points","description":"Stream bullet points generation in real-time.\n\nReturns Server-Sent Events (SSE) stream of the AI response.\nUse this for a better UX with progressive text display.","operationId":"stream_bullet_points_api_v1_thesis__ticker__bullets_stream_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/thesis/{ticker}/generate":{"post":{"tags":["thesis","thesis"],"summary":"Generate Full Thesis","description":"Generate full investment thesis.\n\nUses sonar-deep-research model for comprehensive analysis.\nThis is a user-triggered action (takes 30-60 seconds).\nCached for 30 days.\n\nAuth + rate limit (SHA-452): the underlying Perplexity\nsonar-deep-research call is paid (~30-60s per request) with no\napplication-layer per-user quota, so the route requires a valid\nClerk JWT (``get_current_user_id``) and is capped at 5 requests /\nhour / IP via the ``thesis_generate`` rule in\n``app.middleware.async_rate_limit``. Unauthenticated callers get\n401; bursts past the cap get 429.","operationId":"generate_full_thesis_api_v1_thesis__ticker__generate_post","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"force_refresh","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force Refresh"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/thesis/{ticker}/feedback":{"post":{"tags":["thesis","thesis"],"summary":"Submit Section Feedback","description":"Submit agree/disagree feedback for a thesis section.\n\nAtomically increments the counter in the feedback JSONB column.","operationId":"submit_section_feedback_api_v1_thesis__ticker__feedback_post","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"section","in":"query","required":true,"schema":{"type":"string","title":"Section"}},{"name":"vote","in":"query","required":true,"schema":{"type":"string","title":"Vote"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/thesis/{ticker}":{"get":{"tags":["thesis","thesis"],"summary":"Get Thesis","description":"Get cached thesis if available.\n\nReturns bullets if only bullets are cached.\nReturns full thesis if full thesis is cached.\nReturns 404 if nothing is cached.","operationId":"get_thesis_api_v1_thesis__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leaderboards/dividend":{"get":{"tags":["leaderboards"],"summary":"Get Dividend Leaderboard","description":"Dividend Champions Leaderboard.\n\nRanking: Dividend Score (yield + quality + health composite)\n- Yield Score (40%): 2-6% is sweet spot, >8% penalized\n- Quality Score (30%): Profitable = can afford dividends\n- Health Score (30%): Strong balance sheet = dividend safety","operationId":"get_dividend_leaderboard_api_v1_leaderboards_dividend_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sector filter","title":"Sector"},"description":"Sector filter"},{"name":"market_cap_tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Market cap tier filter","title":"Market Cap Tier"},"description":"Market cap tier filter"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country filter (US, CA, UK)","title":"Country"},"description":"Country filter (US, CA, UK)"},{"name":"include_unqualified","in":"query","required":false,"schema":{"type":"boolean","description":"Include smaller/lower volume stocks","default":false,"title":"Include Unqualified"},"description":"Include smaller/lower volume stocks"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leaderboards/growth":{"get":{"tags":["leaderboards"],"summary":"Get Growth Leaderboard","description":"Growth Leaders Leaderboard.\n\nRanking:\n1. Growth Score (primary) - Revenue + EPS growth\n2. Quality Score (secondary) - Ensures profitable growth\n3. Momentum Score (tertiary) - Market confirmation","operationId":"get_growth_leaderboard_api_v1_leaderboards_growth_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sector filter","title":"Sector"},"description":"Sector filter"},{"name":"market_cap_tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Market cap tier filter","title":"Market Cap Tier"},"description":"Market cap tier filter"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country filter (US, CA, UK)","title":"Country"},"description":"Country filter (US, CA, UK)"},{"name":"include_unqualified","in":"query","required":false,"schema":{"type":"boolean","description":"Include smaller/lower volume stocks","default":false,"title":"Include Unqualified"},"description":"Include smaller/lower volume stocks"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leaderboards/hidden-gems":{"get":{"tags":["leaderboards"],"summary":"Get Hidden Gems Leaderboard","description":"Hidden Gems Leaderboard.\n\nUndervalued small/mid-cap stocks with strong fundamentals.\n\nRanking:\n1. Composite Score (primary) - Overall quality\n2. Valuation Score (secondary) - Price discount\n3. Momentum Score (tertiary) - Market confirmation\n\nFilters:\n- Small to mid cap ($100M - $10B)\n- High composite score (70+)\n- Strong valuation (60+)\n- Quality business (60+)\n- Low or no value trap risk (excludes stocks cheap for good reason)","operationId":"get_hidden_gems_leaderboard_api_v1_leaderboards_hidden_gems_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sector filter","title":"Sector"},"description":"Sector filter"},{"name":"market_cap_tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Market cap tier filter","title":"Market Cap Tier"},"description":"Market cap tier filter"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country filter (US, CA, UK)","title":"Country"},"description":"Country filter (US, CA, UK)"},{"name":"include_unqualified","in":"query","required":false,"schema":{"type":"boolean","description":"Include smaller/lower volume stocks","default":false,"title":"Include Unqualified"},"description":"Include smaller/lower volume stocks"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leaderboards/52w-highs":{"get":{"tags":["leaderboards"],"summary":"Get 52W Highs Leaderboard","description":"52-Week Highs Leaderboard.\n\nReturns stocks trading within 2% of their 52-week high.\nSorted by proximity to high (closest first).\nUses materialized view for fast queries.\n\nFilters: $250M+ market cap, $3+ price, 100K+ volume (excludes penny stocks, ETFs)","operationId":"get_52w_highs_leaderboard_api_v1_leaderboards_52w_highs_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sector filter","title":"Sector"},"description":"Sector filter"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country filter (US, CA, UK)","title":"Country"},"description":"Country filter (US, CA, UK)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Max results","default":50,"title":"Limit"},"description":"Max results"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Offset for pagination","default":0,"title":"Offset"},"description":"Offset for pagination"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leaderboards/52w-lows":{"get":{"tags":["leaderboards"],"summary":"Get 52W Lows Leaderboard","description":"52-Week Lows Leaderboard.\n\nReturns stocks trading within 2% of their 52-week low.\nSorted by proximity to low (closest first).\nUses materialized view for fast queries.\n\nFilters: $250M+ market cap, $3+ price, 100K+ volume (excludes penny stocks, ETFs)","operationId":"get_52w_lows_leaderboard_api_v1_leaderboards_52w_lows_get","parameters":[{"name":"sector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sector filter","title":"Sector"},"description":"Sector filter"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country filter (US, CA, UK)","title":"Country"},"description":"Country filter (US, CA, UK)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Max results","default":50,"title":"Limit"},"description":"Max results"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Offset for pagination","default":0,"title":"Offset"},"description":"Offset for pagination"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/discoveries/new":{"get":{"tags":["discoveries"],"summary":"Get New Finds","description":"Get recently discovered stocks.\n\nReturns stocks that first qualified for leaderboards within the specified days.\nUseful for homepage \"New Finds\" section.","operationId":"get_new_finds_api_v1_discoveries_new_get","parameters":[{"name":"leaderboard_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by leaderboard: value, dividend, growth","title":"Leaderboard Type"},"description":"Filter by leaderboard: value, dividend, growth"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"description":"Days to look back","default":7,"title":"Days"},"description":"Days to look back"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Max results","default":20,"title":"Limit"},"description":"Max results"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get New Finds Api V1 Discoveries New Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/discoveries/update":{"post":{"tags":["discoveries"],"summary":"Run Discovery Update","description":"Manually trigger discovery update.\n\nThis is normally run as part of the daily refresh job.","operationId":"run_discovery_update_api_v1_discoveries_update_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"leaderboard_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Update specific leaderboard or all","title":"Leaderboard Type"},"description":"Update specific leaderboard or all"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Run Discovery Update Api V1 Discoveries Update Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/discoveries/stats":{"get":{"tags":["discoveries"],"summary":"Get Discovery Stats","description":"Get overall discovery statistics.","operationId":"get_discovery_stats_api_v1_discoveries_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Discovery Stats Api V1 Discoveries Stats Get"}}}}}}},"/api/v1/bubble-watch/dashboard":{"get":{"tags":["bubble-watch"],"summary":"Get Bubble Dashboard","description":"Get complete bubble watch dashboard.\n\nReturns the current bubble score, market valuations, breadth indicators,\nsector valuations, and macro indicators.\n\nUses bubble_watch_summary materialized view for fast single-query response.\nFalls back to multi-query approach if view is empty.","operationId":"get_bubble_dashboard_api_v1_bubble_watch_dashboard_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BubbleDashboardResponse"}}}}}}},"/api/v1/bubble-watch/score":{"get":{"tags":["bubble-watch"],"summary":"Get Bubble Score","description":"Get current bubble score.\n\nReturns the latest composite bubble score and component breakdown.","operationId":"get_bubble_score_api_v1_bubble_watch_score_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BubbleScoreResponse"}}}}}}},"/api/v1/bubble-watch/history":{"get":{"tags":["bubble-watch"],"summary":"Get Bubble History","description":"Get historical bubble scores.\n\nReturns daily bubble scores for the specified period.","operationId":"get_bubble_history_api_v1_bubble_watch_history_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":1825,"minimum":7,"description":"Number of days of history","default":365,"title":"Days"},"description":"Number of days of history"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HistoricalBubbleResponse"},"title":"Response Get Bubble History Api V1 Bubble Watch History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bubble-watch/sectors":{"get":{"tags":["bubble-watch"],"summary":"Get Sector Valuations","description":"Get current sector valuations.\n\nReturns valuation metrics for each sector, useful for identifying\nsector-specific bubbles.","operationId":"get_sector_valuations_api_v1_bubble_watch_sectors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SectorValuationResponse"},"type":"array","title":"Response Get Sector Valuations Api V1 Bubble Watch Sectors Get"}}}}}}},"/api/v1/bubble-watch/breadth":{"get":{"tags":["bubble-watch"],"summary":"Get Market Breadth","description":"Get current market breadth indicators.\n\nReturns advance/decline, new highs/lows, and % above moving averages.","operationId":"get_market_breadth_api_v1_bubble_watch_breadth_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketBreadthResponse"}}}}}}},"/api/v1/bubble-watch/valuation":{"get":{"tags":["bubble-watch"],"summary":"Get Market Valuation","description":"Get current market valuation metrics.\n\nReturns market-wide P/E, P/B, P/S ratios and Buffett Indicator.","operationId":"get_market_valuation_api_v1_bubble_watch_valuation_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketValuationResponse"}}}}}}},"/api/v1/bubble-watch/concentration":{"get":{"tags":["bubble-watch"],"summary":"Get Market Concentration","description":"Get current market concentration metrics.\n\nReturns Top 5, Magnificent 7, and Top 10 concentration data.","operationId":"get_market_concentration_api_v1_bubble_watch_concentration_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketConcentrationResponse"}}}}}}},"/api/v1/bubble-watch/margin-debt":{"get":{"tags":["bubble-watch"],"summary":"Get Margin Debt","description":"Get FINRA margin debt data with YoY comparison.\n\nMargin debt is a key indicator of speculative leverage in the market.\nHigh margin debt relative to historical levels signals excessive speculation.","operationId":"get_margin_debt_api_v1_bubble_watch_margin_debt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarginDebtSummaryResponse"}}}}}}},"/api/v1/bubble-watch/margin-debt/history":{"get":{"tags":["bubble-watch"],"summary":"Get Margin Debt History","description":"Get historical margin debt data.\n\nReturns monthly margin debt data for the specified period.\nData available from January 1997 to present.","operationId":"get_margin_debt_history_api_v1_bubble_watch_margin_debt_history_get","parameters":[{"name":"months","in":"query","required":false,"schema":{"type":"integer","maximum":360,"minimum":6,"description":"Number of months of history","default":60,"title":"Months"},"description":"Number of months of history"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarginDebtResponse"},"title":"Response Get Margin Debt History Api V1 Bubble Watch Margin Debt History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bubble-watch/interest-rates":{"get":{"tags":["bubble-watch"],"summary":"Get Interest Rates","description":"Get current interest rates from macro_dashboard_summary materialized view.\n\nReturns Fed Funds rate, Treasury yields across maturities,\nand yield curve spread analysis.\n\nData is pre-computed in the materialized view and refreshed daily.","operationId":"get_interest_rates_api_v1_bubble_watch_interest_rates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InterestRatesResponse"}}}}}}},"/api/v1/bubble-watch/inflation":{"get":{"tags":["bubble-watch"],"summary":"Get Inflation Data","description":"Get current inflation data from macro_dashboard_summary materialized view.\n\nReturns CPI, PCE, and PPI metrics with year-over-year changes.\nData is pre-computed in the materialized view and refreshed daily.","operationId":"get_inflation_data_api_v1_bubble_watch_inflation_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InflationDataResponse"}}}}}}},"/api/v1/bubble-watch/economic-calendar":{"get":{"tags":["bubble-watch"],"summary":"Get Economic Calendar","description":"Get upcoming economic events from cached data.\n\nReturns economic calendar events like Fed meetings, CPI releases,\njobs reports, GDP announcements, etc.\n\nData is refreshed daily by the bubble_watch task.","operationId":"get_economic_calendar_api_v1_bubble_watch_economic_calendar_get","parameters":[{"name":"days_ahead","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"description":"Days ahead to fetch events","default":30,"title":"Days Ahead"},"description":"Days ahead to fetch events"},{"name":"days_back","in":"query","required":false,"schema":{"type":"integer","maximum":7,"minimum":0,"description":"Days back to fetch past events","default":0,"title":"Days Back"},"description":"Days back to fetch past events"},{"name":"country","in":"query","required":false,"schema":{"type":"string","description":"Country code (US, GB, EU, etc.)","default":"US","title":"Country"},"description":"Country code (US, GB, EU, etc.)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EconomicCalendarResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bubble-watch/calculate":{"post":{"tags":["bubble-watch"],"summary":"Trigger Calculation","description":"Trigger bubble indicator calculation.\n\nThis endpoint manually triggers the calculation of all bubble indicators.\nNormally this runs automatically as part of the daily refresh.","operationId":"trigger_calculation_api_v1_bubble_watch_calculate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/bubble-watch/macro/summary":{"get":{"tags":["bubble-watch"],"summary":"Get Macro Summary","description":"Get consolidated macro dashboard data from materialized view.\n\nSingle query returns all macro metrics:\n- Treasury yields (all maturities)\n- Yield curve spreads and status\n- Inflation (PCE Core YoY)\n- Margin debt levels\n- S&P 500 current price\n\nData is pre-computed and refreshed by daily/full bubble watch tasks.","operationId":"get_macro_summary_api_v1_bubble_watch_macro_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MacroSummaryResponse"}}}}}}},"/api/v1/bubble-watch/macro/risk-score":{"get":{"tags":["bubble-watch"],"summary":"Get Macro Risk Score","description":"Get composite macro economic risk score from cached data.\n\nCombines:\n- Yield curve status (30% weight)\n- Margin debt level (25% weight)\n- Inflation vs target (25% weight)\n- Fed policy stance (20% weight)\n\nReturns 0-100 score with risk level classification.\nData is refreshed daily by the bubble_watch task.","operationId":"get_macro_risk_score_api_v1_bubble_watch_macro_risk_score_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MacroRiskScoreResponse"}}}}}}},"/api/v1/bubble-watch/macro/sp500-history":{"get":{"tags":["bubble-watch"],"summary":"Get Sp500 History","description":"Get S&P 500 historical data for correlation overlays.\n\nReturns daily closes aligned with economic indicator dates.\nData is refreshed daily by the bubble_watch task.","operationId":"get_sp500_history_api_v1_bubble_watch_macro_sp500_history_get","parameters":[{"name":"years","in":"query","required":false,"schema":{"type":"integer","maximum":30,"minimum":1,"description":"Years of history (max 30 for full margin debt correlation)","default":5,"title":"Years"},"description":"Years of history (max 30 for full margin debt correlation)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SP500HistoryResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/bubble-watch/macro/event-impacts":{"get":{"tags":["bubble-watch"],"summary":"Get Event Impacts","description":"Get typical market reactions to major economic events.\n\nBased on historical analysis of S&P 500 moves around economic releases.\nData is pre-computed from historical analysis.","operationId":"get_event_impacts_api_v1_bubble_watch_macro_event_impacts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventImpactsResponse"}}}}}}},"/api/v1/bubble-watch/macro/crossovers":{"get":{"tags":["bubble-watch"],"summary":"Get Crossovers","description":"Get historical crossover events (inversions, peaks, pivots).\n\nProvides context for current conditions by showing past similar events\nand subsequent market performance.","operationId":"get_crossovers_api_v1_bubble_watch_macro_crossovers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossoversResponse"}}}}}}},"/api/v1/learn/progress/{user_id}":{"get":{"tags":["learn"],"summary":"Get Learn Progress","description":"Get learning progress for the authenticated user.","operationId":"get_learn_progress_api_v1_learn_progress__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearnProgressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["learn"],"summary":"Save Learn Progress","description":"Save or update learning progress for the authenticated user.","operationId":"save_learn_progress_api_v1_learn_progress__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearnProgressRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearnProgressResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/learn/progress/{user_id}/complete-lesson":{"post":{"tags":["learn"],"summary":"Complete Lesson","description":"Mark a specific lesson as completed for the authenticated user.","operationId":"complete_lesson_api_v1_learn_progress__user_id__complete_lesson_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"module_id","in":"query","required":true,"schema":{"type":"integer","title":"Module Id"}},{"name":"lesson_id","in":"query","required":true,"schema":{"type":"integer","title":"Lesson Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Complete Lesson Api V1 Learn Progress  User Id  Complete Lesson Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/learn/progress/{user_id}/pass-quiz":{"post":{"tags":["learn"],"summary":"Pass Quiz","description":"Mark a quiz as passed for the authenticated user.","operationId":"pass_quiz_api_v1_learn_progress__user_id__pass_quiz_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"module_id","in":"query","required":true,"schema":{"type":"integer","title":"Module Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Pass Quiz Api V1 Learn Progress  User Id  Pass Quiz Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles":{"get":{"tags":["articles","articles"],"summary":"List Articles","description":"List published articles.\n\nReturns articles sorted by published_at descending.\nOnly returns published, non-expired articles.","operationId":"list_articles_api_v1_articles_get","parameters":[{"name":"article_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by article type","title":"Article Type"},"description":"Filter by article type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/bulk":{"get":{"tags":["articles","articles"],"summary":"Bulk List Articles","description":"Bulk articles endpoint for admin/sitemap use.\n\nRequires admin authentication.\nAllows fetching up to 500 articles in a single request.\n\nUse cases:\n- Sitemap generation\n- Data exports\n- Admin dashboards\n\nReturns published, non-expired articles sorted by published_at descending.","operationId":"bulk_list_articles_api_v1_articles_bulk_get","parameters":[{"name":"article_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by article type","title":"Article Type"},"description":"Filter by article type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Number of articles to return (admin-only, max 500)","default":100,"title":"Limit"},"description":"Number of articles to return (admin-only, max 500)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"x-bulk-token","in":"header","required":true,"schema":{"type":"string","title":"X-Bulk-Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/featured":{"get":{"tags":["articles","articles"],"summary":"Get Featured Articles","description":"Get featured articles for homepage display.\n\nReturns the most recent published articles.","operationId":"get_featured_articles_api_v1_articles_featured_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"default":4,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/by-ticker/{ticker}":{"get":{"tags":["articles","articles"],"summary":"Get Articles By Ticker","description":"Get published articles that reference a specific ticker.\n\nReturns articles sorted by published_at descending.\nUsed to integrate ShareValue articles into ticker news feeds.","operationId":"get_articles_by_ticker_api_v1_articles_by_ticker__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":5,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/types":{"get":{"tags":["articles","articles"],"summary":"Get Article Types","description":"Get available article types.","operationId":"get_article_types_api_v1_articles_types_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/articles/{slug}":{"get":{"tags":["articles","articles"],"summary":"Get Article","description":"Get a single article by slug.\n\nReturns full article content for the detail page.","operationId":"get_article_api_v1_articles__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/{slug}/markdown":{"get":{"tags":["articles","articles"],"summary":"Get Article Markdown","description":"Get article in markdown format for AI bot consumption.\n\nReturns plain text markdown with ShareValue.ai branding.","operationId":"get_article_markdown_api_v1_articles__slug__markdown_get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/list":{"get":{"tags":["articles","articles"],"summary":"Admin List Articles","description":"Admin: List all articles including drafts.","operationId":"admin_list_articles_api_v1_articles_admin_list_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"article_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Article Type"}},{"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"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/llm-providers":{"get":{"tags":["articles","articles"],"summary":"Get Llm Providers","description":"Admin: Get available LLM providers and their details.","operationId":"get_llm_providers_api_v1_articles_admin_llm_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/articles/admin/{article_id}":{"get":{"tags":["articles","articles"],"summary":"Admin Get Article","description":"Admin: Get full article details including generation metadata.","operationId":"admin_get_article_api_v1_articles_admin__article_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","title":"Article Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["articles","articles"],"summary":"Admin Update Article","description":"Admin: Update an existing article.","operationId":"admin_update_article_api_v1_articles_admin__article_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","title":"Article Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleCreateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["articles","articles"],"summary":"Admin Delete Article","description":"Admin: Delete an article permanently.","operationId":"admin_delete_article_api_v1_articles_admin__article_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","title":"Article Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/{article_id}/reprocess-tickers":{"post":{"tags":["articles","articles"],"summary":"Admin Reprocess Tickers","description":"Admin: Reprocess ticker tags for an article using updated extraction logic.","operationId":"admin_reprocess_tickers_api_v1_articles_admin__article_id__reprocess_tickers_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","title":"Article Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/{article_id}/tickers":{"put":{"tags":["articles","articles"],"summary":"Admin Update Tickers","description":"Admin: Manually update ticker tags for an article.\n\nThis validates tickers against the database and updates the article's referenced_tickers.","operationId":"admin_update_tickers_api_v1_articles_admin__article_id__tickers_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","title":"Article Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTickersRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/reprocess-all-tickers":{"post":{"tags":["articles","articles"],"summary":"Admin Reprocess All Tickers","description":"Admin: Reprocess ticker tags for all published articles.","operationId":"admin_reprocess_all_tickers_api_v1_articles_admin_reprocess_all_tickers_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/create":{"post":{"tags":["articles","articles"],"summary":"Admin Create Article","description":"Admin: Create a new article manually.","operationId":"admin_create_article_api_v1_articles_admin_create_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleCreateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/articles/admin/{article_id}/publish":{"post":{"tags":["articles","articles"],"summary":"Admin Publish Article","description":"Admin: Publish a draft article.","operationId":"admin_publish_article_api_v1_articles_admin__article_id__publish_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","title":"Article Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/{article_id}/archive":{"post":{"tags":["articles","articles"],"summary":"Admin Archive Article","description":"Admin: Archive an article.","operationId":"admin_archive_article_api_v1_articles_admin__article_id__archive_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"integer","title":"Article Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/generate":{"post":{"tags":["articles","articles"],"summary":"Admin Generate Article","description":"Admin: Generate a new article using AI.\n\nSupports multiple LLM providers (Perplexity, Gemini).\nProvider can be specified in request or defaults to LLM_PROVIDER env var.\n\nArticle types:\n- daily_value_picks: Best value stocks identified today\n- hidden_gems: Undervalued small/mid-cap stocks\n- market_outlook: Economic conditions and market analysis\n- sector_spotlight: Deep dive into a specific sector\n- custom: Custom topic (requires topic parameter)","operationId":"admin_generate_article_api_v1_articles_admin_generate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"auto_publish","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Auto Publish"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleGenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/generate-agentic":{"post":{"tags":["articles","articles"],"summary":"Admin Generate Article Agentic","description":"Admin: Generate a new article using the agentic multi-agent system.\n\nDispatches a Celery background task to avoid HTTP timeout (the 8-phase\npipeline takes 6-10+ minutes). Returns a job_id for polling progress.\n\nPoll GET /articles/admin/article-job/{job_id} for status updates.","operationId":"admin_generate_article_agentic_api_v1_articles_admin_generate_agentic_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"auto_publish","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Auto Publish"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleGenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/admin/article-job/{job_id}":{"get":{"tags":["articles","articles"],"summary":"Get Article Job Status","description":"Poll the status of an async agentic article generation job.\n\nReturns progress updates during generation and the full article on completion.","operationId":"get_article_job_status_api_v1_articles_admin_article_job__job_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/prompts":{"get":{"tags":["articles"],"summary":"List Prompt Templates","description":"List all prompt templates.\n\nReturns templates from database if they exist, otherwise returns defaults.","operationId":"list_prompt_templates_api_v1_articles_prompts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PromptTemplateResponse"},"type":"array","title":"Response List Prompt Templates Api V1 Articles Prompts Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/articles/prompts/{article_type}":{"get":{"tags":["articles"],"summary":"Get Prompt Template","description":"Get prompt template for specific article type.\n\nReturns custom template if exists, otherwise returns default.","operationId":"get_prompt_template_api_v1_articles_prompts__article_type__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_type","in":"path","required":true,"schema":{"type":"string","title":"Article Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["articles"],"summary":"Update Prompt Template","description":"Update prompt template for specific article type.\n\nCreates new template if doesn't exist, otherwise updates existing.","operationId":"update_prompt_template_api_v1_articles_prompts__article_type__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_type","in":"path","required":true,"schema":{"type":"string","title":"Article Type"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["articles"],"summary":"Delete Prompt Template","description":"Delete custom prompt template for specific article type.\n\nReturns to using default prompts from code.","operationId":"delete_prompt_template_api_v1_articles_prompts__article_type__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_type","in":"path","required":true,"schema":{"type":"string","title":"Article Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/prompts/{article_type}/reset":{"post":{"tags":["articles"],"summary":"Reset Prompt Template","description":"Reset prompt template to default for specific article type.\n\nDeletes custom template if exists, returning to code defaults.","operationId":"reset_prompt_template_api_v1_articles_prompts__article_type__reset_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_type","in":"path","required":true,"schema":{"type":"string","title":"Article Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTemplateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/blog":{"get":{"tags":["blog"],"summary":"List Posts","description":"Paginated list of published posts, newest first.\n\nOptional `?tag=` filter performs an exact-string containment check on the\nJSONB tags array (uses the GIN index from idx_blog_posts_tags_gin).","operationId":"list_posts_api_v1_blog_get","parameters":[{"name":"tag","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"description":"Filter by tag (exact match against the tags array)","title":"Tag"},"description":"Filter by tag (exact match against the tags array)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/blog/sitemap":{"get":{"tags":["blog"],"summary":"List Sitemap","description":"Slug + updated_at for every published post.\n\nConsumed by `mvo-frontend/app/sitemap.ts` to register /blog/{slug} URLs.","operationId":"list_sitemap_api_v1_blog_sitemap_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/BlogSitemapEntry"},"type":"array","title":"Response List Sitemap Api V1 Blog Sitemap Get"}}}}}}},"/api/v1/blog/{slug}":{"get":{"tags":["blog"],"summary":"Get Post","description":"Get a single published post by slug. 404 on draft/archived/missing.","operationId":"get_post_api_v1_blog__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","maxLength":255,"title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/blog/posts":{"post":{"tags":["blog-admin"],"summary":"Create Post","description":"Create a new blog post.\n\nDefaults status to \"draft\". If ``status=\"published\"`` is supplied, sets\n``published_at`` to now (UTC) so the DB CHECK constraint\n``ck_blog_posts_published_at_not_null_when_published`` is satisfied.\n\nReturns 201 with the created row. Returns 409 on slug conflict, 422 on\ninvalid status (not in {draft, published, archived}).","operationId":"create_post_api_v1_admin_blog_posts_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostAdminResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["blog-admin"],"summary":"List Posts","description":"List ALL blog posts (drafts + published + archived), newest first.\n\nSort order is ``updated_at DESC`` — for the admin UI we care about\n\"what was edited recently\", not \"what was published\". Published-time\nsort lives on the public endpoint.","operationId":"list_posts_api_v1_admin_blog_posts_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","maximum":100000,"minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostAdminListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/blog/posts/{post_id}":{"put":{"tags":["blog-admin"],"summary":"Update Post","description":"Update an existing blog post.\n\nOnly fields present in the request body are updated. The published_at\ntimestamp follows these rules:\n\n* draft -> published with published_at currently NULL: set to now (UTC).\n* draft -> published with published_at already set: preserve it (the\n  post was previously published and unpublished; honour the original).\n* any other transition: leave published_at untouched.\n\nReturns 404 if the post doesn't exist, 409 if a slug change collides\nwith another row, 422 on an invalid status value.","operationId":"update_post_api_v1_admin_blog_posts__post_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"integer","title":"Post Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostAdminResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["blog-admin"],"summary":"Get Post","description":"Fetch a single post by id, including drafts and archived posts.\n\nKeyed on numeric id (not slug) so the admin UI can drive edits even\nwhen the slug is being renamed mid-session. 404 on a missing id.","operationId":"get_post_api_v1_admin_blog_posts__post_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"post_id","in":"path","required":true,"schema":{"type":"integer","title":"Post Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostAdminResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/analytics/cost-analytics":{"get":{"tags":["article-analytics"],"summary":"Get Cost Analytics","description":"Get comprehensive cost analytics for article generation.\n\nReturns:\n- Total costs and trends\n- Cost breakdown by model/type\n- Daily cost trends\n- Cost per article metrics\n- Token usage statistics\n- Efficiency metrics","operationId":"get_cost_analytics_api_v1_articles_analytics_cost_analytics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/articles/analytics/cost-projections":{"get":{"tags":["article-analytics"],"summary":"Get Cost Projections","description":"Get cost projections based on recent trends.","operationId":"get_cost_projections_api_v1_articles_analytics_cost_projections_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/ai-costs/analytics":{"get":{"tags":["ai-cost-analytics"],"summary":"Get Ai Cost Analytics","description":"Get comprehensive cost analytics across all AI features.\n\nReturns:\n- Overall metrics (requests, cost, tokens, latency, errors)\n- Comparison with prior period\n- Feature breakdown\n- Model breakdown\n- Daily trends\n- Article costs\n- Grand total cost","operationId":"get_ai_cost_analytics_api_v1_ai_costs_analytics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ai-costs/budget-status":{"get":{"tags":["ai-cost-analytics"],"summary":"Get Budget Status","description":"Quick check: has today's AI spend crossed the daily budget threshold?\n\nReturns cost, budget, percentage used, and an alert level\n(ok / warning at 70% / critical at 90%).","operationId":"get_budget_status_api_v1_ai_costs_budget_status_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"daily_budget","in":"query","required":false,"schema":{"type":"number","default":10.0,"title":"Daily Budget"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ai-costs/my-usage":{"get":{"tags":["ai-cost-analytics"],"summary":"Get My Ai Usage","description":"Get AI usage for the authenticated user.\n\nuser_id comes from the Clerk JWT (validated against JWKS in prod;\nfalls back to X-User-Id only when CLERK_JWKS_URL is unset on\ndev/staging).","operationId":"get_my_ai_usage_api_v1_ai_costs_my_usage_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ai-costs/conversations":{"get":{"tags":["ai-cost-analytics"],"summary":"Get Chat Conversations","description":"Get chat conversation cost breakdown.\n\nReturns recent conversations with total cost, tokens, and model used,\nplus summary totals.","operationId":"get_chat_conversations_api_v1_ai_costs_conversations_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":7,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ai-costs/projections":{"get":{"tags":["ai-cost-analytics"],"summary":"Get Ai Cost Projections","description":"Get cost projections based on recent 30-day trends.\n\nReturns daily averages and monthly/yearly projections,\nbroken down by feature (stock_chat, nl_screener, articles).","operationId":"get_ai_cost_projections_api_v1_ai_costs_projections_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/special-occasions/active":{"get":{"tags":["special-occasions"],"summary":"Get Active Special Occasion","description":"Get the currently active special occasion based on date range","operationId":"get_active_special_occasion_api_v1_special_occasions_active_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/SpecialOccasionResponse"},{"type":"null"}],"title":"Response Get Active Special Occasion Api V1 Special Occasions Active Get"}}}}}}},"/api/v1/special-occasions/":{"get":{"tags":["special-occasions"],"summary":"List Special Occasions","description":"List all special occasions","operationId":"list_special_occasions_api_v1_special_occasions__get","parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SpecialOccasionResponse"},"title":"Response List Special Occasions Api V1 Special Occasions  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["special-occasions"],"summary":"Create Special Occasion","description":"Create a new special occasion","operationId":"create_special_occasion_api_v1_special_occasions__post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecialOccasionCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecialOccasionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/special-occasions/{occasion_id}":{"get":{"tags":["special-occasions"],"summary":"Get Special Occasion","description":"Get a specific special occasion by ID","operationId":"get_special_occasion_api_v1_special_occasions__occasion_id__get","parameters":[{"name":"occasion_id","in":"path","required":true,"schema":{"type":"integer","title":"Occasion Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecialOccasionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["special-occasions"],"summary":"Update Special Occasion","description":"Update a special occasion","operationId":"update_special_occasion_api_v1_special_occasions__occasion_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"occasion_id","in":"path","required":true,"schema":{"type":"integer","title":"Occasion Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecialOccasionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecialOccasionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["special-occasions"],"summary":"Delete Special Occasion","description":"Delete a special occasion","operationId":"delete_special_occasion_api_v1_special_occasions__occasion_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"occasion_id","in":"path","required":true,"schema":{"type":"integer","title":"Occasion Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"title":"Response Delete Special Occasion Api V1 Special Occasions  Occasion Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/stats/overview":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Overview Stats","description":"Get overview statistics for news tracking\n\nReturns high-level metrics about news coverage across all tickers and sources.","operationId":"get_overview_stats_api_v1_news_analytics_stats_overview_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"description":"Time window in hours (max 30 days)","default":24,"title":"Hours"},"description":"Time window in hours (max 30 days)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/frequency/ticker":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Top Tickers","description":"Get top tickers by news volume\n\nReturns list of tickers with most articles in time window.","operationId":"get_top_tickers_api_v1_news_analytics_frequency_ticker_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":24,"title":"Hours"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/frequency/by-ticker/{ticker}":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Ticker Frequency","description":"Get news frequency statistics for a specific ticker\n\nReturns:\n- Total articles in time window\n- Articles per hour\n- Breakdown by source\n- Sentiment distribution","operationId":"get_ticker_frequency_api_v1_news_analytics_frequency_by_ticker__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":24,"title":"Hours"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/frequency/source":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Top Sources","description":"Get top sources by news volume\n\nReturns list of sources with most articles in time window.","operationId":"get_top_sources_api_v1_news_analytics_frequency_source_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":24,"title":"Hours"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/frequency/by-source/{source}":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Source Frequency","description":"Get publishing frequency statistics for a specific source\n\nReturns:\n- Total articles in time window\n- Articles per hour\n- Top tickers covered\n- Publishing patterns","operationId":"get_source_frequency_api_v1_news_analytics_frequency_by_source__source__get","parameters":[{"name":"source","in":"path","required":true,"schema":{"type":"string","title":"Source"}},{"name":"hours","in":"query","required":false,"schema":{"type":"integer","maximum":720,"minimum":1,"default":24,"title":"Hours"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/heatmap":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Publishing Heatmap","description":"Get publishing pattern heatmap data\n\nReturns hour-of-day vs day-of-week article counts for visualization.","operationId":"get_publishing_heatmap_api_v1_news_analytics_heatmap_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"ticker","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ticker"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/competitive-gaps":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Competitive Gaps","description":"Identify tickers with low news coverage (opportunities for ShareValue)\n\nReturns tickers with fewer than min_coverage articles per day.","operationId":"get_competitive_gaps_api_v1_news_analytics_competitive_gaps_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"min_coverage","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Minimum articles/day threshold","default":5,"title":"Min Coverage"},"description":"Minimum articles/day threshold"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/admin/competitive-gaps":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Competitive Gaps","description":"Identify tickers with low news coverage (opportunities for ShareValue)\n\nReturns tickers with fewer than min_coverage articles per day.","operationId":"get_competitive_gaps_api_v1_news_analytics_admin_competitive_gaps_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"min_coverage","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Minimum articles/day threshold","default":5,"title":"Min Coverage"},"description":"Minimum articles/day threshold"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/headline-patterns":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Headline Patterns","description":"Analyze headline patterns and keywords\n\nReturns common words, length distribution, sentiment patterns.","operationId":"get_headline_patterns_api_v1_news_analytics_headline_patterns_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"ticker","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ticker"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/refresh-views":{"post":{"tags":["news-analytics","news-analytics"],"summary":"Refresh Analytics Views","description":"Refresh all news analytics materialized views\n\nShould be run after significant data updates or periodically.\nIncludes both basic and advanced strategic views.\nAdmin-only endpoint.","operationId":"refresh_analytics_views_api_v1_news_analytics_refresh_views_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/source-rankings/{ticker}":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Source Rankings","description":"Get source rankings for a ticker\n\nShows which sources publish most frequently about this ticker.","operationId":"get_source_rankings_api_v1_news_analytics_source_rankings__ticker__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/strategy/hourly-velocity":{"get":{"tags":["news-analytics-strategy"],"summary":"Get Hourly Velocity","description":"Hourly publishing velocity analysis\n\nShows articles per hour by source, day of week patterns, and consistency metrics.\nCritical for identifying optimal publishing windows.","operationId":"get_hourly_velocity_api_v1_news_analytics_strategy_hourly_velocity_get","parameters":[{"name":"source","in":"query","required":false,"schema":{"type":"string","description":"Filter by specific source","title":"Source"},"description":"Filter by specific source"},{"name":"day_of_week","in":"query","required":false,"schema":{"type":"integer","maximum":6,"minimum":0,"description":"0=Sunday, 6=Saturday","title":"Day Of Week"},"description":"0=Sunday, 6=Saturday"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/strategy/market-cap-tiers":{"get":{"tags":["news-analytics-strategy"],"summary":"Get Market Cap Analysis","description":"Market cap tier coverage analysis\n\nShows which market cap tiers have the most/least coverage.\nCritical for identifying white space opportunities.","operationId":"get_market_cap_analysis_api_v1_news_analytics_strategy_market_cap_tiers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/news-analytics/strategy/competitive-matrix":{"get":{"tags":["news-analytics-strategy"],"summary":"Get Competitive Matrix","description":"Competitive positioning matrix\n\nCompares all news sources across volume, breadth, velocity, consistency.\nIdentifies your competitive position and strategy opportunities.","operationId":"get_competitive_matrix_api_v1_news_analytics_strategy_competitive_matrix_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/news-analytics/strategy/opportunity-windows":{"get":{"tags":["news-analytics-strategy"],"summary":"Get Opportunity Windows","description":"Temporal opportunity windows\n\nIdentifies hours/days with low competition - optimal times to publish\nfor maximum visibility with minimal noise.\n\nTimezone options:\n- UTC: Coordinated Universal Time (default)\n- PST: Pacific Standard Time (UTC-8)\n- EST: Eastern Standard Time (UTC-5)","operationId":"get_opportunity_windows_api_v1_news_analytics_strategy_opportunity_windows_get","parameters":[{"name":"min_opportunity","in":"query","required":false,"schema":{"type":"string","description":"Filter by opportunity level","title":"Min Opportunity"},"description":"Filter by opportunity level"},{"name":"timezone","in":"query","required":false,"schema":{"type":"string","description":"Timezone for display (UTC, PST, EST)","default":"UTC","title":"Timezone"},"description":"Timezone for display (UTC, PST, EST)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/strategy/coverage-concentration":{"get":{"tags":["news-analytics-strategy"],"summary":"Get Coverage Concentration","description":"Coverage concentration analysis (Top 20/50/100)\n\nShows how coverage is concentrated on top tickers vs long tail.\nCritical for identifying if market is too focused on mega-caps.","operationId":"get_coverage_concentration_api_v1_news_analytics_strategy_coverage_concentration_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/news-analytics/strategy/recommendations":{"get":{"tags":["news-analytics-strategy"],"summary":"Get Strategic Recommendations","description":"Strategic recommendations based on all analytics\n\nSynthesizes all metrics into actionable content strategy recommendations.\nAdmin-only endpoint.","operationId":"get_strategic_recommendations_api_v1_news_analytics_strategy_recommendations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/strategy/refresh-views":{"post":{"tags":["news-analytics-strategy"],"summary":"Refresh Strategy Views","description":"Refresh all strategic analytics materialized views\n\nShould be run periodically (daily or after significant data updates).\nAdmin-only endpoint.","operationId":"refresh_strategy_views_api_v1_news_analytics_strategy_refresh_views_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/metrics/market-efficiency":{"get":{"tags":["news-analytics-metrics"],"summary":"Get Market Efficiency Metrics","description":"Market Efficiency Metrics\n\nMeasures how efficiently news coverage is distributed across market cap tiers.\nKey metrics:\n- Gini coefficient (coverage inequality)\n- Herfindahl-Hirschman Index (market concentration)\n- Coverage efficiency ratio","operationId":"get_market_efficiency_metrics_api_v1_news_analytics_metrics_market_efficiency_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/metrics/content-quality":{"get":{"tags":["news-analytics-metrics"],"summary":"Get Content Quality Metrics","description":"Content Quality Indicators\n\nMeasures content quality and engagement potential:\n- Headline quality metrics\n- Sentiment consistency\n- Source diversity index\n- Ticker prominence in headlines","operationId":"get_content_quality_metrics_api_v1_news_analytics_metrics_content_quality_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/metrics/competitive-positioning":{"get":{"tags":["news-analytics-metrics"],"summary":"Get Competitive Positioning Metrics","description":"Competitive Positioning Analytics\n\nAnalyzes competitive landscape and positioning opportunities:\n- Market share by source\n- Competitive intensity by hour/day\n- White space opportunities\n- Competitive moats","operationId":"get_competitive_positioning_metrics_api_v1_news_analytics_metrics_competitive_positioning_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/metrics/risk-opportunity":{"get":{"tags":["news-analytics-metrics"],"summary":"Get Risk Opportunity Metrics","description":"Risk and Opportunity Scoring\n\nIdentifies risks and opportunities in content strategy:\n- Coverage gaps (high-value, low-coverage tickers)\n- Saturation risks (over-covered tickers)\n- Emerging trends (velocity changes)\n- Strategic opportunities","operationId":"get_risk_opportunity_metrics_api_v1_news_analytics_metrics_risk_opportunity_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":7,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/heatmaps/velocity":{"get":{"tags":["news-analytics-heatmaps"],"summary":"Get Velocity Heatmap","description":"Publishing Velocity Heatmap - Hour × Day Grid\n\nShows when articles are published by hour and day of week.\n\n**Why this matters**: Identifies low-competition time windows for maximum visibility.\n\n**Action**: Publish during \"blue zones\" (low article count) to stand out.\n\nReturns 24×7 grid with article counts, unique tickers, and sentiment by time slot.","operationId":"get_velocity_heatmap_api_v1_news_analytics_heatmaps_velocity_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[a-zA-Z0-9\\s\\-\\.]+$"},{"type":"null"}],"description":"Filter by specific source","title":"Source"},"description":"Filter by specific source"},{"name":"timezone_offset","in":"query","required":false,"schema":{"type":"integer","maximum":14,"minimum":-12,"description":"Timezone offset from UTC","default":0,"title":"Timezone Offset"},"description":"Timezone offset from UTC"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/heatmaps/competition":{"get":{"tags":["news-analytics-heatmaps"],"summary":"Get Competition Heatmap","description":"Competition Intensity Heatmap\n\nShows when competition is highest/lowest by hour and day.\n\n**Why this matters**: Publishing during high-competition windows means your content gets buried.\n\n**Action**: Target green zones (high opportunity score) for 3-5x better visibility.\n\nOpportunity score: 100 = zero competition, 0 = maximum competition","operationId":"get_competition_heatmap_api_v1_news_analytics_heatmaps_competition_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"min_opportunity_score","in":"query","required":false,"schema":{"type":"number","maximum":100.0,"minimum":0.0,"default":0,"title":"Min Opportunity Score"}},{"name":"timezone_offset","in":"query","required":false,"schema":{"type":"integer","maximum":14,"minimum":-12,"default":0,"title":"Timezone Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/insights/daily":{"get":{"tags":["news-analytics-heatmaps"],"summary":"Get Daily Insights","description":"Daily Actionable Insights\n\nTop priority actions for today based on:\n- Optimal publishing windows\n- White space opportunities\n- Trending topics\n- Saturation risks\n\n**Why this matters**: Cuts through noise to show exactly what to do today.\n\n**Action**: Execute top 3 recommendations before noon for best results.","operationId":"get_daily_insights_api_v1_news_analytics_insights_daily_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"default":5,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/insights/opportunities":{"get":{"tags":["news-analytics-heatmaps"],"summary":"Get Opportunity Pipeline","description":"White Space Opportunity Pipeline\n\nTop under-covered tickers with high potential.\n\n**Why this matters**: Less competition = more visibility and engagement.\n\n**Action**: Allocate 40% of content capacity to top 20 opportunities.\n\nOpportunity score factors:\n- Coverage gap (40%): How under-covered vs peers\n- Quality score (30%): Fundamental strength\n- Momentum (20%): Price/volume trends\n- Market cap tier (10%): Optimal size for differentiation","operationId":"get_opportunity_pipeline_api_v1_news_analytics_insights_opportunities_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"min_score","in":"query","required":false,"schema":{"type":"number","maximum":100.0,"minimum":0.0,"default":50,"title":"Min Score"}},{"name":"market_cap_tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Cap Tier"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":10,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/trends/momentum":{"get":{"tags":["news-analytics-heatmaps"],"summary":"Get Momentum Trends","description":"Weekly Momentum Trends\n\nTickers with explosive coverage growth.\n\n**Why this matters**: Early coverage on trending topics = thought leadership.\n\n**Action**: Cover trending tickers 2-3 days before peak for maximum impact.\n\nMomentum status:\n- Explosive Growth: 100%+ increase week-over-week\n- Strong Growth: 50%+ increase\n- Moderate Growth: 20%+ increase","operationId":"get_momentum_trends_api_v1_news_analytics_trends_momentum_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"min_change_pct","in":"query","required":false,"schema":{"type":"number","minimum":0.0,"default":20,"title":"Min Change Pct"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":5,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/refresh-heatmaps":{"post":{"tags":["news-analytics-heatmaps"],"summary":"Refresh Heatmap Views","description":"Refresh all heatmap and insight materialized views\n\nRun this after article backfill or daily at 2 AM.\nUses advisory lock to prevent concurrent refreshes.","operationId":"refresh_heatmap_views_api_v1_news_analytics_refresh_heatmaps_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/headlines/patterns":{"get":{"tags":["news-analytics-headlines"],"summary":"Get Headline Patterns","description":"Headline Pattern Analysis\n\nShows which headline structures are most common and effective.\n\n**Patterns identified:**\n- Numbered List: \"3 Stocks to Buy Now\"\n- Question Format: \"Is AAPL a Buy?\"\n- Action/Rating: \"Upgrade TSLA to Buy\"\n- Earnings Report: \"MSFT Beats Q3 Earnings\"\n- Price Movement: \"NVDA Surges 15%\"\n- Colon Structure: \"AAPL: Why It's a Buy\"\n- Superlative/Ranking: \"Top 5 Tech Stocks\"\n\n**Why this matters**: Different patterns attract different audiences and contexts.\n\n**Action**: Use top 3 patterns for 70% of content, experiment with others for variety.","operationId":"get_headline_patterns_api_v1_news_analytics_headlines_patterns_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/headlines/length-optimization":{"get":{"tags":["news-analytics-headlines"],"summary":"Get Length Optimization","description":"Headline Length Optimization\n\nIdentifies optimal headline length for engagement and clarity.\n\n**Why this matters**:\n- Too short: Lacks context, low SEO value\n- Too long: Gets truncated, loses impact\n- Sweet spot: 55-65 characters (Twitter-optimized)\n\n**Action**: Aim for 60-80 characters, 8-12 words for maximum impact.","operationId":"get_length_optimization_api_v1_news_analytics_headlines_length_optimization_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/headlines/ticker-placement":{"get":{"tags":["news-analytics-headlines"],"summary":"Get Ticker Placement Analysis","description":"Ticker Placement Strategy\n\nAnalyzes where ticker symbols should appear in headlines.\n\n**Placement options:**\n- Start: \"$AAPL: Why It's a Buy\" (direct, clear)\n- Middle: \"Why AAPL Is a Buy Now\" (natural flow)\n- End: \"Top Tech Stock: AAPL\" (suspense, ranking)\n- Not Present: \"Apple Earnings Beat\" (brand name instead)\n\n**Why this matters**: Ticker placement affects scannability and SEO.\n\n**Action**: Use ticker at start for ratings/analysis, middle for narratives.","operationId":"get_ticker_placement_analysis_api_v1_news_analytics_headlines_ticker_placement_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/headlines/word-analysis":{"get":{"tags":["news-analytics-headlines"],"summary":"Get Word Analysis","description":"Word Choice Analysis\n\nIdentifies high-impact words and their sentiment associations.\n\n**Word categories:**\n- Action/Rating: buy, sell, upgrade, downgrade\n- Earnings: beat, miss, guidance, revenue\n- Positive Movement: surge, soar, rally, jump\n- Negative Movement: plunge, crash, drop, fall\n- Superlatives: top, best, worst, leading\n- Urgency: breaking, alert, now, today\n\n**Why this matters**: Word choice drives clicks and sets expectations.\n\n**Action**: Use positive movement words for gains, avoid hyperbole for credibility.","operationId":"get_word_analysis_api_v1_news_analytics_headlines_word_analysis_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^[a-zA-Z0-9\\s\\/\\-]+$"},{"type":"null"}],"title":"Category"}},{"name":"min_frequency","in":"query","required":false,"schema":{"type":"integer","minimum":5,"default":10,"title":"Min Frequency"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":10,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/headlines/templates":{"get":{"tags":["news-analytics-headlines"],"summary":"Get Headline Templates","description":"Winning Headline Templates\n\nProven headline formulas used by top sources.\n\n**Template examples:**\n- \"[N] Stocks to Buy Now\"\n- \"[TICKER]: Why It's a Buy\"\n- \"[QUESTION] Should You Buy [TICKER]?\"\n- \"[TICKER] Surges [X]% on Earnings Beat\"\n- \"Upgrade [TICKER] to Buy\"\n\n**Why this matters**: Templates provide proven structures to follow.\n\n**Action**: Adapt top 5 templates to your content, customize with unique insights.","operationId":"get_headline_templates_api_v1_news_analytics_headlines_templates_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"min_usage","in":"query","required":false,"schema":{"type":"integer","minimum":3,"default":5,"title":"Min Usage"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":5,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/headlines/competitive-styles":{"get":{"tags":["news-analytics-headlines"],"summary":"Get Competitive Styles","description":"Competitive Headline Styles\n\nHow top sources structure their headlines.\n\n**Styles identified:**\n- Ticker-Focused: 80%+ headlines include ticker\n- List-Based: 30%+ start with numbers\n- Question-Heavy: 20%+ are questions\n- Structured (Colon): 50%+ use colon format\n- Concise: <50 characters average\n- Descriptive: >80 characters average\n\n**Why this matters**: Understand competitor strategies to differentiate.\n\n**Action**: Identify gaps in competitor styles, own an underserved format.","operationId":"get_competitive_styles_api_v1_news_analytics_headlines_competitive_styles_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"min_headlines","in":"query","required":false,"schema":{"type":"integer","minimum":5,"default":10,"title":"Min Headlines"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/backfill":{"post":{"tags":["news-analytics","news-analytics"],"summary":"Trigger Backfill","operationId":"trigger_backfill_api_v1_news_analytics_backfill_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackfillRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/backfill/status":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Backfill Status","description":"Get status of news tracking data\n\nReturns statistics about tracked articles to help determine if backfill is needed.\nAdmin-only endpoint.","operationId":"get_backfill_status_api_v1_news_analytics_backfill_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/news-analytics/backfill/completed-tickers":{"get":{"tags":["news-analytics","news-analytics"],"summary":"Get Completed Tickers","description":"Get list of tickers that already have sufficient historical data\n\nUseful for resuming a backfill - skip tickers that are already complete.\nAdmin-only endpoint.","operationId":"get_completed_tickers_api_v1_news_analytics_backfill_completed_tickers_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":730,"minimum":1,"description":"Days back to check for coverage","default":365,"title":"Days"},"description":"Days back to check for coverage"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Max tickers to return","default":1000,"title":"Limit"},"description":"Max tickers to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Offset for pagination","default":0,"title":"Offset"},"description":"Offset for pagination"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/test-news-backfill":{"get":{"tags":["admin"],"summary":"Test News Backfill","description":"Test EODHD News API to see how many articles are available historically.\n\nThis helps determine backfill feasibility and API call requirements.","operationId":"test_news_backfill_api_v1_admin_test_news_backfill_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"ticker","in":"query","required":false,"schema":{"type":"string","description":"Ticker to test","default":"AAPL","title":"Ticker"},"description":"Ticker to test"},{"name":"days","in":"query","required":false,"schema":{"type":"integer","description":"Days to look back (default 2 years)","default":730,"title":"Days"},"description":"Days to look back (default 2 years)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Test News Backfill Api V1 Admin Test News Backfill Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/news-analytics/admin/refresh-views":{"post":{"tags":["news-analytics-admin"],"summary":"Refresh News Analytics Views","description":"Refresh all news analytics materialized views.\n\nThis endpoint refreshes:\n- news_velocity_heatmap\n- news_competition_heatmap\n- news_weekly_momentum\n- news_opportunity_scores\n- news_daily_insights","operationId":"refresh_news_analytics_views_api_v1_news_analytics_admin_refresh_views_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Refresh News Analytics Views Api V1 News Analytics Admin Refresh Views Post"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/value-wall/sectors":{"get":{"tags":["value-wall"],"summary":"Get Sectors Summary","description":"Get sector summary with top stocks per sector for Value Wall home view.\n\nReturns:\n    - List of sectors with stock counts\n    - Top N stocks per sector\n    - Industry counts per sector","operationId":"get_sectors_summary_api_v1_value_wall_sectors_get","parameters":[{"name":"limit_per_sector","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Number of top stocks per sector","default":10,"title":"Limit Per Sector"},"description":"Number of top stocks per sector"},{"name":"include_penny_stocks","in":"query","required":false,"schema":{"type":"boolean","description":"Include stocks <$5 or <$300M market cap","default":false,"title":"Include Penny Stocks"},"description":"Include stocks <$5 or <$300M market cap"},{"name":"include_shell_companies","in":"query","required":false,"schema":{"type":"boolean","description":"Include shell companies","default":false,"title":"Include Shell Companies"},"description":"Include shell companies"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/value-wall/sectors/{sector}/industries":{"get":{"tags":["value-wall"],"summary":"Get Sector Industries","description":"Get industry breakdown for a specific sector with top stocks per industry.\n\nArgs:\n    sector: Sector name (e.g., \"Technology\")\n    limit_per_industry: Number of top stocks to return per industry\n\nReturns:\n    - Sector info\n    - List of industries with top stocks\n    - Overall sector top stocks","operationId":"get_sector_industries_api_v1_value_wall_sectors__sector__industries_get","parameters":[{"name":"sector","in":"path","required":true,"schema":{"type":"string","title":"Sector"}},{"name":"limit_per_industry","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Number of top stocks per industry","default":10,"title":"Limit Per Industry"},"description":"Number of top stocks per industry"},{"name":"include_penny_stocks","in":"query","required":false,"schema":{"type":"boolean","description":"Include stocks <$5 or <$300M market cap","default":false,"title":"Include Penny Stocks"},"description":"Include stocks <$5 or <$300M market cap"},{"name":"include_shell_companies","in":"query","required":false,"schema":{"type":"boolean","description":"Include shell companies","default":false,"title":"Include Shell Companies"},"description":"Include shell companies"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/value-wall/industries/{industry}":{"get":{"tags":["value-wall"],"summary":"Get Industry Stocks","description":"Get all stocks in a specific industry, sorted by composite score.\n\nArgs:\n    industry: Industry name (e.g., \"Software - Application\")\n    limit: Number of stocks to return\n    offset: Pagination offset\n\nReturns:\n    - Industry info\n    - Sector name\n    - All stocks in industry (paginated)","operationId":"get_industry_stocks_api_v1_value_wall_industries__industry__get","parameters":[{"name":"industry","in":"path","required":true,"schema":{"type":"string","title":"Industry"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Number of stocks to return","default":100,"title":"Limit"},"description":"Number of stocks to return"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Offset for pagination","default":0,"title":"Offset"},"description":"Offset for pagination"},{"name":"include_penny_stocks","in":"query","required":false,"schema":{"type":"boolean","description":"Include stocks <$5 or <$300M market cap","default":false,"title":"Include Penny Stocks"},"description":"Include stocks <$5 or <$300M market cap"},{"name":"include_shell_companies","in":"query","required":false,"schema":{"type":"boolean","description":"Include shell companies","default":false,"title":"Include Shell Companies"},"description":"Include shell companies"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stats/universe":{"get":{"tags":["stats"],"summary":"Get Universe Stats","description":"Returns live counts powering the hero section:\n- ticker_count: total active securities across all enabled exchanges\n- country_count: distinct countries covered\n- exchange_count: number of enabled exchanges","operationId":"get_universe_stats_api_v1_stats_universe_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Universe Stats Api V1 Stats Universe Get"}}}}}}},"/api/v1/stats/exchanges":{"get":{"tags":["stats"],"summary":"Get Exchange Stats","description":"Detailed exchange and country coverage stats.\n\nReturns per-exchange and per-country breakdowns with live stock counts\nfrom the database. Enabled exchanges include active/qualified ticker counts;\ndisabled (upcoming) exchanges show zero counts with their rollout phase.\n\nIntended for:\n- Frontend country/exchange selector components\n- Marketing pages showing platform coverage\n- Internal services that need to know which markets are live","operationId":"get_exchange_stats_api_v1_stats_exchanges_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Exchange Stats Api V1 Stats Exchanges Get"}}}}}}},"/api/v1/chat/{ticker}/message":{"post":{"tags":["chat"],"summary":"Send Chat Message","description":"Send a chat message and stream AI response.\n\nReturns Server-Sent Events with JSON payloads:\n- {\"type\": \"chunk\", \"content\": \"...\"} — streamed text\n- {\"type\": \"done\", \"conversation_id\": N, \"remaining\": M} — completion\n- {\"type\": \"error\", \"content\": \"...\"} — error","operationId":"send_chat_message_api_v1_chat__ticker__message_post","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatMessageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/{ticker}/starters":{"get":{"tags":["chat"],"summary":"Get Starters","description":"Get contextual conversation starter questions.","operationId":"get_starters_api_v1_chat__ticker__starters_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Starters Api V1 Chat  Ticker  Starters Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/{ticker}/conversations":{"get":{"tags":["chat"],"summary":"List Conversations","description":"List user's conversations for a ticker.","operationId":"list_conversations_api_v1_chat__ticker__conversations_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response List Conversations Api V1 Chat  Ticker  Conversations Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/chat/{ticker}/conversations/{conversation_id}":{"get":{"tags":["chat"],"summary":"Get Conversation","description":"Get a conversation with its messages.","operationId":"get_conversation_api_v1_chat__ticker__conversations__conversation_id__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"conversation_id","in":"path","required":true,"schema":{"type":"integer","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Conversation Api V1 Chat  Ticker  Conversations  Conversation Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolio":{"get":{"tags":["portfolio"],"summary":"List Portfolios","description":"List user's portfolios with ticker membership set.","operationId":"list_portfolios_api_v1_portfolio_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["portfolio"],"summary":"Create Portfolio","description":"Create a new portfolio.","operationId":"create_portfolio_api_v1_portfolio_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePortfolioRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolio/combine":{"post":{"tags":["portfolio"],"summary":"Combine Portfolios","description":"Create a new portfolio by combining holdings from multiple portfolios.","operationId":"combine_portfolios_api_v1_portfolio_combine_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CombinePortfoliosRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolio/{portfolio_id}":{"get":{"tags":["portfolio"],"summary":"Get Portfolio","description":"Get portfolio with aggregated scores.","operationId":"get_portfolio_api_v1_portfolio__portfolio_id__get","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"integer","title":"Portfolio Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["portfolio"],"summary":"Update Portfolio","description":"Update portfolio holdings.","operationId":"update_portfolio_api_v1_portfolio__portfolio_id__put","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"integer","title":"Portfolio Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePortfolioRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["portfolio"],"summary":"Delete Portfolio","description":"Delete a portfolio.","operationId":"delete_portfolio_api_v1_portfolio__portfolio_id__delete","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"integer","title":"Portfolio Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolio/{portfolio_id}/holdings":{"post":{"tags":["portfolio"],"summary":"Add Holding","description":"Add a single holding to a portfolio (atomic append).","operationId":"add_holding_api_v1_portfolio__portfolio_id__holdings_post","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"integer","title":"Portfolio Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddHoldingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolio/{portfolio_id}/analyze":{"post":{"tags":["portfolio"],"summary":"Analyze Portfolio","description":"Stream AI analysis of portfolio. Returns Server-Sent Events.","operationId":"analyze_portfolio_api_v1_portfolio__portfolio_id__analyze_post","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"integer","title":"Portfolio Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/portfolio/{portfolio_id}/upload":{"post":{"tags":["portfolio"],"summary":"Upload Holdings File","description":"Parse brokerage export file(s) and return extracted holdings for review.\n\nAccepts multiple files. Supported: CSV, XLS, XLSX, PDF, PNG, JPG.\nImages (screenshots of brokerage statements) are parsed via Gemini vision.","operationId":"upload_holdings_file_api_v1_portfolio__portfolio_id__upload_post","parameters":[{"name":"portfolio_id","in":"path","required":true,"schema":{"type":"integer","title":"Portfolio Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_holdings_file_api_v1_portfolio__portfolio_id__upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/watchlist/lists":{"get":{"tags":["watchlist"],"summary":"List Watchlists","description":"List all watchlists for user with item counts.","operationId":"list_watchlists_api_v1_watchlist_lists_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["watchlist"],"summary":"Create Watchlist List","description":"Create a new named watchlist.","operationId":"create_watchlist_list_api_v1_watchlist_lists_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWatchlistListRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/watchlist/lists/{watchlist_id}":{"put":{"tags":["watchlist"],"summary":"Rename Watchlist","description":"Rename a watchlist.","operationId":"rename_watchlist_api_v1_watchlist_lists__watchlist_id__put","parameters":[{"name":"watchlist_id","in":"path","required":true,"schema":{"type":"integer","title":"Watchlist Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameWatchlistRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["watchlist"],"summary":"Delete Watchlist List","description":"Delete a watchlist. Items are moved to the default watchlist. Cannot delete default.","operationId":"delete_watchlist_list_api_v1_watchlist_lists__watchlist_id__delete","parameters":[{"name":"watchlist_id","in":"path","required":true,"schema":{"type":"integer","title":"Watchlist Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/watchlist":{"get":{"tags":["watchlist"],"summary":"List Watchlist","description":"List user's watchlist items with current scores.\n\nIf watchlist_id is provided, returns items from that watchlist only.\nOtherwise returns all items across all watchlists (backward compatible).","operationId":"list_watchlist_api_v1_watchlist_get","parameters":[{"name":"watchlist_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Filter by watchlist; omit for all items","title":"Watchlist Id"},"description":"Filter by watchlist; omit for all items"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["watchlist"],"summary":"Add To Watchlist","description":"Add a stock to user's watchlist. Defaults to the default watchlist if watchlist_id omitted.","operationId":"add_to_watchlist_api_v1_watchlist_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddWatchlistRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/watchlist/{ticker}":{"delete":{"tags":["watchlist"],"summary":"Remove From Watchlist","description":"Remove a stock from user's watchlist.","operationId":"remove_from_watchlist_api_v1_watchlist__ticker__delete","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"watchlist_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Remove from specific watchlist; omit for default","title":"Watchlist Id"},"description":"Remove from specific watchlist; omit for default"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/watchlist/check/{ticker}":{"get":{"tags":["watchlist"],"summary":"Check Watchlist","description":"Check if a stock is in any of user's watchlists.","operationId":"check_watchlist_api_v1_watchlist_check__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/brokerage/connect":{"post":{"tags":["brokerage"],"summary":"Initiate Connection","description":"Generate SnapTrade connection portal URL.","operationId":"initiate_connection_api_v1_brokerage_connect_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Initiate Connection Api V1 Brokerage Connect Post"}}}}}}},"/api/v1/brokerage/connections":{"get":{"tags":["brokerage"],"summary":"List Connections","description":"List user's brokerage connections.","operationId":"list_connections_api_v1_brokerage_connections_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response List Connections Api V1 Brokerage Connections Get"}}}}}}},"/api/v1/brokerage/connections/{connection_id}/sync":{"post":{"tags":["brokerage"],"summary":"Sync Connection","description":"Manually trigger a holdings sync for a connection.","operationId":"sync_connection_api_v1_brokerage_connections__connection_id__sync_post","parameters":[{"name":"connection_id","in":"path","required":true,"schema":{"type":"integer","title":"Connection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Sync Connection Api V1 Brokerage Connections  Connection Id  Sync Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/brokerage/finalize":{"post":{"tags":["brokerage"],"summary":"Finalize Connection","description":"Finalize a pending brokerage connection after the user completes the SnapTrade portal.\n\nCalled by frontend after popup closes. Checks SnapTrade API directly for\ncompleted connections, activates them, and syncs holdings to create a portfolio.","operationId":"finalize_connection_api_v1_brokerage_finalize_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Finalize Connection Api V1 Brokerage Finalize Post"}}}}}}},"/api/v1/brokerage/connections/{connection_id}":{"delete":{"tags":["brokerage"],"summary":"Disconnect Brokerage","description":"Disconnect a brokerage connection.","operationId":"disconnect_brokerage_api_v1_brokerage_connections__connection_id__delete","parameters":[{"name":"connection_id","in":"path","required":true,"schema":{"type":"integer","title":"Connection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Disconnect Brokerage Api V1 Brokerage Connections  Connection Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/brokerage/webhook":{"post":{"tags":["brokerage"],"summary":"Snaptrade Webhook","description":"Receive SnapTrade webhook events.\n\nThree-layer defense: HMAC signature → eventTimestamp replay-window\ncheck → webhookId/eventId nonce dedup. See\n``snaptrade_service.handle_webhook``.\n\nStatus-code semantics:\n- 401: signature mismatch OR stale eventTimestamp (replay window).\n- 400: malformed body (invalid JSON, missing/unparseable timestamp).\n- 503: idempotency subsystem unavailable (Redis down) — \"retry me\".\n- 200 with action=duplicate_ignored: replay caught by nonce dedup.\n- 200 with status=error: unhandled internal exception (kept to\n  prevent retry storms; Sentry surfaces the real bug).\n\nResponse ``detail`` strings are intentionally generic to avoid\nleaking internal infrastructure hints (replay-window length,\nRedis status) to anyone who can hit the endpoint. Verbose context\nstays in server logs only.","operationId":"snaptrade_webhook_api_v1_brokerage_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Snaptrade Webhook Api V1 Brokerage Webhook Post"}}}}}}},"/api/v1/alerts":{"get":{"tags":["alerts"],"summary":"List Alerts","description":"List user's alerts with ticker details.","operationId":"list_alerts_api_v1_alerts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["alerts"],"summary":"Create Alert","description":"Create a new alert rule.","operationId":"create_alert_api_v1_alerts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/alerts/{alert_id}":{"delete":{"tags":["alerts"],"summary":"Delete Alert","description":"Delete an alert (cascades notifications).","operationId":"delete_alert_api_v1_alerts__alert_id__delete","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"integer","title":"Alert Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/alerts/{alert_id}/toggle":{"patch":{"tags":["alerts"],"summary":"Toggle Alert","description":"Toggle an alert active/inactive.","operationId":"toggle_alert_api_v1_alerts__alert_id__toggle_patch","parameters":[{"name":"alert_id","in":"path","required":true,"schema":{"type":"integer","title":"Alert Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/alerts/notifications":{"get":{"tags":["alerts"],"summary":"List Notifications","description":"List notifications (unread first, latest 50).","operationId":"list_notifications_api_v1_alerts_notifications_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/alerts/notifications/count":{"get":{"tags":["alerts"],"summary":"Unread Count","description":"Get unread notification count (lightweight for polling).","operationId":"unread_count_api_v1_alerts_notifications_count_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/alerts/notifications/{notification_id}/read":{"post":{"tags":["alerts"],"summary":"Mark Read","description":"Mark a notification as read.","operationId":"mark_read_api_v1_alerts_notifications__notification_id__read_post","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"integer","title":"Notification Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/alerts/notifications/read-all":{"post":{"tags":["alerts"],"summary":"Mark All Read","description":"Mark all notifications as read.","operationId":"mark_all_read_api_v1_alerts_notifications_read_all_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/alerts/notifications/{notification_id}":{"delete":{"tags":["alerts"],"summary":"Dismiss Notification","description":"Dismiss (delete) a notification.","operationId":"dismiss_notification_api_v1_alerts_notifications__notification_id__delete","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"integer","title":"Notification Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/homepage/feed":{"get":{"tags":["homepage"],"summary":"Homepage Feed","description":"Personalized homepage feed for authenticated users, trending for anonymous.","operationId":"homepage_feed_api_v1_homepage_feed_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Homepage Feed Api V1 Homepage Feed Get"}}}}}}},"/api/v1/credits/balance":{"get":{"tags":["credits"],"summary":"Get Balance","description":"Get current credit balance for the authenticated user.","operationId":"get_balance_api_v1_credits_balance_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Balance Api V1 Credits Balance Get"}}}}}}},"/api/v1/credits/transactions":{"get":{"tags":["credits"],"summary":"Get Transactions","description":"Get credit transaction history for the authenticated user.","operationId":"get_transactions_api_v1_credits_transactions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Transactions Api V1 Credits Transactions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/credits/costs":{"get":{"tags":["credits"],"summary":"Get Costs","description":"Get current credit costs per feature (public, includes display names).","operationId":"get_costs_api_v1_credits_costs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"object"},"type":"array","title":"Response Get Costs Api V1 Credits Costs Get"}}}}}}},"/api/v1/subscription/status":{"get":{"tags":["subscription"],"summary":"Get Status","description":"Get current subscription status for the authenticated user.","operationId":"get_status_api_v1_subscription_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Get Status Api V1 Subscription Status Get"}}}}}}},"/api/v1/subscription/trial":{"post":{"tags":["subscription"],"summary":"Start Trial","description":"Start a 7-day free trial (no credit card required).","operationId":"start_trial_api_v1_subscription_trial_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Start Trial Api V1 Subscription Trial Post"}}}}}}},"/api/v1/subscription/cancel":{"post":{"tags":["subscription"],"summary":"Cancel","description":"Cancel subscription at end of current period.","operationId":"cancel_api_v1_subscription_cancel_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Cancel Api V1 Subscription Cancel Post"}}}}}}},"/api/v1/webhooks/stripe-event":{"post":{"tags":["webhooks"],"summary":"Handle Stripe Event","description":"Process Stripe webhook events forwarded from Next.js.\n\nThe Next.js webhook verifies the Stripe signature and forwards\nrelevant data to this internal endpoint.","operationId":"handle_stripe_event_api_v1_webhooks_stripe_event_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StripeEventPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/webhooks/clerk":{"post":{"tags":["webhooks"],"summary":"Handle Clerk Event","description":"Verify svix signature → on user.deleted, cascade-delete per-user rows.\n\nAlways responds 200 to verified-and-handled deliveries (idempotent on\nre-delivery — second call deletes 0 rows, still returns 200). Rejects\nunsigned or tampered requests with 401. Cascade failures return 500 so\nClerk retries the delivery; the handler is idempotent so retries are safe.","operationId":"handle_clerk_event_api_v1_webhooks_clerk_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Handle Clerk Event Api V1 Webhooks Clerk Post"}}}}}}},"/api/v1/admin/credits/costs":{"get":{"tags":["admin-credits"],"summary":"Get Credit Costs","description":"Get all feature credit costs.","operationId":"get_credit_costs_api_v1_admin_credits_costs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"object"},"type":"array","title":"Response Get Credit Costs Api V1 Admin Credits Costs Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/credits/costs/{feature}":{"put":{"tags":["admin-credits"],"summary":"Update Credit Cost","description":"Update credit cost and/or display name for a feature.","operationId":"update_credit_cost_api_v1_admin_credits_costs__feature__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"feature","in":"path","required":true,"schema":{"type":"string","title":"Feature"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCreditCostRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Update Credit Cost Api V1 Admin Credits Costs  Feature  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/credits/users":{"get":{"tags":["admin-credits"],"summary":"Get User Credits","description":"Get credit usage overview for all users (from ai_usage + credit_balances).","operationId":"get_user_credits_api_v1_admin_credits_users_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"},"title":"Response Get User Credits Api V1 Admin Credits Users Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/credits/adjust/{user_id}":{"post":{"tags":["admin-credits"],"summary":"Adjust User Credits","description":"Admin credit adjustment (add or remove credits).","operationId":"adjust_user_credits_api_v1_admin_credits_adjust__user_id__post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdjustCreditsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","title":"Response Adjust User Credits Api V1 Admin Credits Adjust  User Id  Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/etf/screener/results":{"get":{"tags":["etf"],"summary":"Get Etf Screener","description":"Screen ETFs with filters and sorting. Returns paginated results.","operationId":"get_etf_screener_api_v1_etf_screener_results_get","parameters":[{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Sort by: overall_score, performance_score, cost_score, risk_score, total_assets, net_expense_ratio, yield_ttm","default":"overall_score","title":"Sort By"},"description":"Sort by: overall_score, performance_score, cost_score, risk_score, total_assets, net_expense_ratio, yield_ttm"},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Morningstar category filter","title":"Category"},"description":"Morningstar category filter"},{"name":"min_overall_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Overall Score"}},{"name":"min_total_assets","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Minimum AUM in dollars","title":"Min Total Assets"},"description":"Minimum AUM in dollars"},{"name":"max_expense_ratio","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Maximum expense ratio (e.g., 0.005 = 0.5%)","title":"Max Expense Ratio"},"description":"Maximum expense ratio (e.g., 0.005 = 0.5%)"},{"name":"min_yield","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Minimum TTM yield","title":"Min Yield"},"description":"Minimum TTM yield"},{"name":"min_morningstar","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":5,"minimum":1},{"type":"null"}],"description":"Minimum Morningstar rating","title":"Min Morningstar"},"description":"Minimum Morningstar rating"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/etf/leaderboards/{leaderboard_type}":{"get":{"tags":["etf"],"summary":"Get Etf Leaderboard","description":"Get ETF leaderboards by type.\n\nTypes: top_rated, lowest_cost, highest_yield, best_performance, most_diversified","operationId":"get_etf_leaderboard_api_v1_etf_leaderboards__leaderboard_type__get","parameters":[{"name":"leaderboard_type","in":"path","required":true,"schema":{"type":"string","title":"Leaderboard Type"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by Morningstar category","title":"Category"},"description":"Filter by Morningstar category"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":25,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/etf/categories/list":{"get":{"tags":["etf"],"summary":"Get Etf Categories","description":"Get all available ETF categories with counts.","operationId":"get_etf_categories_api_v1_etf_categories_list_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/etf/stats/overview":{"get":{"tags":["etf"],"summary":"Get Etf Stats","description":"Get ETF Hub overview statistics.","operationId":"get_etf_stats_api_v1_etf_stats_overview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/etf/{ticker}/performance":{"get":{"tags":["etf"],"summary":"Get Etf Performance","description":"Return indexed price returns (base 100) for the ETF and its exchange benchmark.\n\nUsed to render the Performance vs Benchmark chart on the ETF detail page.\nBoth series are normalized to 100 at the first overlapping trading date in\nthe requested period.","operationId":"get_etf_performance_api_v1_etf__ticker__performance_get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}},{"name":"period","in":"query","required":false,"schema":{"type":"string","pattern":"^(ytd|1y|3y|5y)$","default":"1y","title":"Period"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/etf/{ticker}":{"get":{"tags":["etf"],"summary":"Get Etf Profile","description":"Get full ETF profile with scores, metrics, and fundamentals.","operationId":"get_etf_profile_api_v1_etf__ticker__get","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","title":"Ticker"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Root","description":"Root endpoint.","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health Check","description":"Health check endpoint.\n\nVerifies DB and Redis connectivity. Returns 200 if both are up,\n503 if either is down.  Used by Railway to route traffic away from\ndead instances.","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health/pool":{"get":{"summary":"Pool Metrics","description":"Database connection pool metrics.\n\nExposes SQLAlchemy pool stats for monitoring dashboards.\nReturns pool size, checked-out/available connections, and overflow.\nIn development (NullPool), returns a notice instead of pool stats.","operationId":"pool_metrics_health_pool_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AddHoldingRequest":{"properties":{"ticker":{"type":"string","maxLength":20,"minLength":1,"title":"Ticker"},"shares":{"type":"number","exclusiveMinimum":0.0,"title":"Shares","default":1.0},"cost_basis":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Basis"}},"type":"object","required":["ticker"],"title":"AddHoldingRequest"},"AddWatchlistRequest":{"properties":{"ticker":{"type":"string","maxLength":20,"title":"Ticker"},"watchlist_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Watchlist Id","description":"Target watchlist ID; omit for default"},"note":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Note"}},"type":"object","required":["ticker"],"title":"AddWatchlistRequest"},"AdjustCreditsRequest":{"properties":{"amount":{"type":"integer","maximum":10000.0,"minimum":-10000.0,"title":"Amount"},"reason":{"type":"string","maxLength":500,"minLength":1,"title":"Reason"}},"type":"object","required":["amount","reason"],"title":"AdjustCreditsRequest"},"ArticleCreateRequest":{"properties":{"title":{"type":"string","title":"Title"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"article_type":{"type":"string","title":"Article Type","default":"custom"},"summary_bullets":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Summary Bullets"},"content_sections":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Content Sections"},"featured_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Featured Image Url"},"referenced_tickers":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Referenced Tickers"},"referenced_pages":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Referenced Pages"},"meta_title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meta Title"},"meta_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meta Description"},"status":{"type":"string","title":"Status","default":"draft"},"generation_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Generation Cost"},"generation_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Generation Tokens"},"generation_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generation Model"}},"type":"object","required":["title"],"title":"ArticleCreateRequest","description":"Request to create/update an article."},"ArticleGenerateRequest":{"properties":{"article_type":{"type":"string","title":"Article Type"},"topic":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Topic"},"sector":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sector"},"llm_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Provider"},"llm_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Model"},"ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ticker"},"length":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Length","default":"medium"},"sentiment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sentiment"},"writing_angle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writing Angle"},"headline_style":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline Style"},"variety_seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Variety Seed"},"narrative_structure":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Narrative Structure"},"analytical_depth":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analytical Depth"},"audience_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience Level"},"content_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Format"},"temporal_focus":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Temporal Focus"},"specificity_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Specificity Level"}},"type":"object","required":["article_type"],"title":"ArticleGenerateRequest","description":"Request to generate an article using AI."},"BackfillRequest":{"properties":{"tickers":{"type":"integer","maximum":6400.0,"minimum":1.0,"title":"Tickers","description":"Number of top tickers to backfill","default":500},"days":{"type":"integer","maximum":730.0,"minimum":1.0,"title":"Days","description":"Days to look back","default":365},"skip_tickers":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Skip Tickers","description":"List of tickers to skip (for resume, max 1000)"},"force":{"type":"boolean","title":"Force","description":"Force backfill even if ticker already has data","default":false},"dry_run":{"type":"boolean","title":"Dry Run","description":"Run in dry-run mode (no database writes)","default":false}},"type":"object","title":"BackfillRequest"},"BlogListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/BlogPostSummary"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["items","total","limit","offset"],"title":"BlogListResponse"},"BlogPostAdminListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/BlogPostAdminResponse"},"type":"array","title":"Items"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["items","total","limit","offset"],"title":"BlogPostAdminListResponse","description":"Paginated admin listing — same shape as the public listing minus\nthe published-only filter, plus id + status + created_at so the UI\ncan render publish toggles and sort."},"BlogPostAdminResponse":{"properties":{"id":{"type":"integer","title":"Id"},"slug":{"type":"string","title":"Slug"},"title":{"type":"string","title":"Title"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"content_md":{"type":"string","title":"Content Md"},"author":{"type":"string","title":"Author"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"status":{"type":"string","title":"Status"},"featured_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Featured Image Url"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Published At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","slug","title","subtitle","summary","content_md","author","tags","status","featured_image_url","published_at","created_at","updated_at"],"title":"BlogPostAdminResponse","description":"Admin-facing projection — includes drafts + all timestamps."},"BlogPostCreate":{"properties":{"slug":{"type":"string","maxLength":255,"minLength":1,"title":"Slug"},"title":{"type":"string","maxLength":500,"minLength":1,"title":"Title"},"content_md":{"type":"string","minLength":1,"title":"Content Md"},"subtitle":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Subtitle"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"author":{"type":"string","maxLength":255,"minLength":1,"title":"Author","default":"ShareValue.ai team"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"featured_image_url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Featured Image Url"},"status":{"type":"string","title":"Status","default":"draft"}},"type":"object","required":["slug","title","content_md"],"title":"BlogPostCreate","description":"Request body for POST /api/v1/admin/blog/posts.\n\nRequired: slug, title, content_md. Everything else has a sensible default.\nStatus defaults to \"draft\" — explicit publish requires the PUT endpoint."},"BlogPostDetail":{"properties":{"slug":{"type":"string","title":"Slug"},"title":{"type":"string","title":"Title"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"content_md":{"type":"string","title":"Content Md"},"author":{"type":"string","title":"Author"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Published At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"featured_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Featured Image Url"}},"type":"object","required":["slug","title","subtitle","summary","content_md","author","tags","published_at","updated_at","featured_image_url"],"title":"BlogPostDetail","description":"Detail-page projection — full markdown body."},"BlogPostSummary":{"properties":{"slug":{"type":"string","title":"Slug"},"title":{"type":"string","title":"Title"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"author":{"type":"string","title":"Author"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Published At"},"featured_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Featured Image Url"}},"type":"object","required":["slug","title","subtitle","summary","author","tags","published_at","featured_image_url"],"title":"BlogPostSummary","description":"Listing-page projection — no full markdown body."},"BlogPostUpdate":{"properties":{"slug":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Slug"},"title":{"anyOf":[{"type":"string","maxLength":500,"minLength":1},{"type":"null"}],"title":"Title"},"content_md":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Content Md"},"subtitle":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Subtitle"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"author":{"anyOf":[{"type":"string","maxLength":255,"minLength":1},{"type":"null"}],"title":"Author"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"featured_image_url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Featured Image Url"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},"type":"object","title":"BlogPostUpdate","description":"Request body for PUT /api/v1/admin/blog/posts/{post_id}.\n\nAll fields optional — only provided fields are updated. Setting\n``status`` to \"published\" on a post whose ``published_at`` is null\nwill populate ``published_at`` to now (UTC). Subsequent updates do NOT\nbump ``published_at`` — the original publish time is preserved."},"BlogSitemapEntry":{"properties":{"slug":{"type":"string","title":"Slug"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["slug","updated_at"],"title":"BlogSitemapEntry"},"Body_upload_holdings_file_api_v1_portfolio__portfolio_id__upload_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files"}},"type":"object","required":["files"],"title":"Body_upload_holdings_file_api_v1_portfolio__portfolio_id__upload_post"},"BubbleDashboardResponse":{"properties":{"bubble_score":{"$ref":"#/components/schemas/BubbleScoreResponse"},"market_valuation":{"anyOf":[{"$ref":"#/components/schemas/MarketValuationResponse"},{"type":"null"}]},"market_breadth":{"anyOf":[{"$ref":"#/components/schemas/MarketBreadthResponse"},{"type":"null"}]},"market_concentration":{"anyOf":[{"$ref":"#/components/schemas/MarketConcentrationResponse"},{"type":"null"}]},"sector_valuations":{"items":{"$ref":"#/components/schemas/SectorValuationResponse"},"type":"array","title":"Sector Valuations","default":[]},"macro_indicators":{"items":{"$ref":"#/components/schemas/MacroIndicatorResponse"},"type":"array","title":"Macro Indicators","default":[]},"historical_scores":{"items":{"type":"object"},"type":"array","title":"Historical Scores","default":[]}},"type":"object","required":["bubble_score"],"title":"BubbleDashboardResponse","description":"Complete bubble watch dashboard data."},"BubbleScoreResponse":{"properties":{"calculation_date":{"type":"string","format":"date","title":"Calculation Date"},"bubble_score":{"type":"number","title":"Bubble Score","description":"Composite bubble score (0-100)"},"bubble_level":{"type":"string","title":"Bubble Level","description":"Risk level: low, moderate, elevated, high, extreme"},"valuation_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Valuation Score"},"concentration_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Concentration Score"},"sentiment_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sentiment Score"},"leverage_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Leverage Score"},"breadth_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Breadth Score"},"macro_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Macro Score"},"raw_indicators":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Raw Indicators"}},"type":"object","required":["calculation_date","bubble_score","bubble_level"],"title":"BubbleScoreResponse","description":"Current bubble score and components."},"ChatMessageRequest":{"properties":{"message":{"type":"string","maxLength":2000,"minLength":1,"title":"Message"},"session_id":{"type":"string","maxLength":100,"minLength":1,"title":"Session Id"},"conversation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Conversation Id"}},"type":"object","required":["message","session_id"],"title":"ChatMessageRequest","description":"Chat message request."},"CombinePortfoliosRequest":{"properties":{"portfolio_ids":{"items":{"type":"integer"},"type":"array","minItems":2,"title":"Portfolio Ids"}},"type":"object","required":["portfolio_ids"],"title":"CombinePortfoliosRequest"},"ConcentrationTickerResponse":{"properties":{"ticker":{"type":"string","title":"Ticker"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"market_cap_billions":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Market Cap Billions"},"weight_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Weight Pct"}},"type":"object","required":["ticker"],"title":"ConcentrationTickerResponse","description":"Individual ticker in concentration data."},"CreateAlertRequest":{"properties":{"ticker":{"type":"string","maxLength":20,"title":"Ticker"},"alert_type":{"type":"string","pattern":"^(price_target|score_change)$","title":"Alert Type"},"condition":{"type":"object","title":"Condition"}},"type":"object","required":["ticker","alert_type","condition"],"title":"CreateAlertRequest"},"CreatePortfolioRequest":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","default":"My Portfolio"},"holdings":{"items":{"$ref":"#/components/schemas/HoldingInput"},"type":"array","title":"Holdings"}},"type":"object","title":"CreatePortfolioRequest"},"CreateWatchlistListRequest":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"CreateWatchlistListRequest"},"CrossoverEvent":{"properties":{"date":{"type":"string","title":"Date"},"event_type":{"type":"string","title":"Event Type"},"description":{"type":"string","title":"Description"},"sp500_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sp500 Price"},"subsequent_move_1m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Subsequent Move 1M"},"subsequent_move_3m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Subsequent Move 3M"},"subsequent_move_12m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Subsequent Move 12M"}},"type":"object","required":["date","event_type","description"],"title":"CrossoverEvent","description":"Historical economic crossover event."},"CrossoversResponse":{"properties":{"yield_curve_inversions":{"items":{"$ref":"#/components/schemas/CrossoverEvent"},"type":"array","title":"Yield Curve Inversions"},"margin_debt_peaks":{"items":{"$ref":"#/components/schemas/CrossoverEvent"},"type":"array","title":"Margin Debt Peaks"},"fed_pivots":{"items":{"$ref":"#/components/schemas/CrossoverEvent"},"type":"array","title":"Fed Pivots"}},"type":"object","required":["yield_curve_inversions","margin_debt_peaks","fed_pivots"],"title":"CrossoversResponse","description":"Historical crossover events for context."},"EconomicCalendarResponse":{"properties":{"events":{"items":{"$ref":"#/components/schemas/EconomicEventResponse"},"type":"array","title":"Events"},"from_date":{"type":"string","title":"From Date"},"to_date":{"type":"string","title":"To Date"},"country":{"type":"string","title":"Country"},"total_events":{"type":"integer","title":"Total Events"}},"type":"object","required":["events","from_date","to_date","country","total_events"],"title":"EconomicCalendarResponse","description":"Economic calendar with events."},"EconomicEventResponse":{"properties":{"date":{"type":"string","title":"Date"},"time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Time"},"country":{"type":"string","title":"Country"},"event":{"type":"string","title":"Event"},"importance":{"type":"string","title":"Importance","description":"low, medium, or high","default":"medium"},"actual":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actual"},"forecast":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Forecast"},"previous":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous"},"change":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change"},"change_percentage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change Percentage"}},"type":"object","required":["date","country","event"],"title":"EconomicEventResponse","description":"Economic calendar event."},"EventImpact":{"properties":{"event_type":{"type":"string","title":"Event Type"},"avg_move_pct":{"type":"number","title":"Avg Move Pct","description":"Average absolute S&P 500 move on release day"},"positive_surprise_move":{"type":"number","title":"Positive Surprise Move","description":"Avg move on positive surprise"},"negative_surprise_move":{"type":"number","title":"Negative Surprise Move","description":"Avg move on negative surprise"},"typical_direction":{"type":"string","title":"Typical Direction","description":"Expected market direction if data beats"},"sample_size":{"type":"integer","title":"Sample Size"},"last_impact":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Impact"}},"type":"object","required":["event_type","avg_move_pct","positive_surprise_move","negative_surprise_move","typical_direction","sample_size"],"title":"EventImpact","description":"Typical market impact for an economic event type."},"EventImpactsResponse":{"properties":{"impacts":{"items":{"$ref":"#/components/schemas/EventImpact"},"type":"array","title":"Impacts"},"methodology":{"type":"string","title":"Methodology"}},"type":"object","required":["impacts","methodology"],"title":"EventImpactsResponse","description":"Typical market impacts for major economic events."},"FedRateResponse":{"properties":{"rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rate"},"target_low":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Target Low"},"target_high":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Target High"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"}},"type":"object","title":"FedRateResponse","description":"Federal Funds Rate data."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HistoricalBubbleResponse":{"properties":{"calculation_date":{"type":"string","format":"date","title":"Calculation Date"},"bubble_score":{"type":"number","title":"Bubble Score"},"bubble_level":{"type":"string","title":"Bubble Level"}},"type":"object","required":["calculation_date","bubble_score","bubble_level"],"title":"HistoricalBubbleResponse","description":"Historical bubble score data point."},"HoldingInput":{"properties":{"ticker":{"type":"string","maxLength":20,"minLength":1,"title":"Ticker"},"shares":{"type":"number","exclusiveMinimum":0.0,"title":"Shares"},"cost_basis":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Basis"}},"type":"object","required":["ticker","shares"],"title":"HoldingInput"},"InflationDataResponse":{"properties":{"cpi_headline":{"$ref":"#/components/schemas/InflationMetricResponse"},"cpi_core":{"$ref":"#/components/schemas/InflationMetricResponse"},"pce_headline":{"$ref":"#/components/schemas/InflationMetricResponse"},"pce_core":{"$ref":"#/components/schemas/InflationMetricResponse"},"ppi":{"$ref":"#/components/schemas/InflationMetricResponse"},"fed_target":{"type":"number","title":"Fed Target","default":2.0},"overall_status":{"type":"string","title":"Overall Status"},"last_updated":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Updated"}},"type":"object","required":["cpi_headline","cpi_core","pce_headline","pce_core","ppi","overall_status"],"title":"InflationDataResponse","description":"Complete inflation data."},"InflationMetricResponse":{"properties":{"name":{"type":"string","title":"Name"},"current":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Current"},"prior":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Prior"},"change":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"}},"type":"object","required":["name"],"title":"InflationMetricResponse","description":"Single inflation metric."},"IngestTickerRequest":{"properties":{"ticker":{"type":"string","title":"Ticker"}},"type":"object","required":["ticker"],"title":"IngestTickerRequest","description":"Request body for single ticker ingestion."},"InterestRatesResponse":{"properties":{"fed_funds":{"$ref":"#/components/schemas/FedRateResponse"},"treasury_yields":{"items":{"$ref":"#/components/schemas/TreasuryYieldResponse"},"type":"array","title":"Treasury Yields"},"yield_spreads":{"items":{"$ref":"#/components/schemas/YieldSpreadResponse"},"type":"array","title":"Yield Spreads"},"yield_curve_status":{"type":"string","title":"Yield Curve Status"},"last_updated":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Updated"}},"type":"object","required":["fed_funds","treasury_yields","yield_spreads","yield_curve_status"],"title":"InterestRatesResponse","description":"Complete interest rates data."},"JobParams":{"properties":{"start_chunk":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Chunk"},"force_scoring":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force Scoring","default":false},"months":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Months","default":13},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"years":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Years","default":30},"exchange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exchange"},"force_update":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force Update","default":false},"skip_weekend_check":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Skip Weekend Check","default":false},"staleness_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Staleness Days"},"max_tickers":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tickers"},"force_recalculate":{"type":"boolean","title":"Force Recalculate","default":false},"quarters":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Quarters"}},"type":"object","title":"JobParams","description":"Optional parameters for job execution."},"LearnProgressRequest":{"properties":{"lessons_completed":{"items":{"type":"string"},"type":"array","title":"Lessons Completed"},"quizzes_passed":{"items":{"type":"string"},"type":"array","title":"Quizzes Passed"},"last_visited":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Visited"}},"type":"object","required":["lessons_completed","quizzes_passed"],"title":"LearnProgressRequest","description":"Request body for updating learn progress"},"LearnProgressResponse":{"properties":{"lessons_completed":{"items":{"type":"string"},"type":"array","title":"Lessons Completed"},"quizzes_passed":{"items":{"type":"string"},"type":"array","title":"Quizzes Passed"},"last_visited":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Visited"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["lessons_completed","quizzes_passed","last_visited","updated_at"],"title":"LearnProgressResponse","description":"Response body for learn progress"},"MacroIndicatorResponse":{"properties":{"indicator_code":{"type":"string","title":"Indicator Code"},"indicator_name":{"type":"string","title":"Indicator Name"},"latest_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latest Value"},"latest_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Latest Date"},"prior_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Prior Value"},"change_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change Pct"}},"type":"object","required":["indicator_code","indicator_name"],"title":"MacroIndicatorResponse","description":"Macro economic indicator."},"MacroRiskScoreResponse":{"properties":{"score":{"type":"number","maximum":100.0,"minimum":0.0,"title":"Score","description":"Composite risk score 0-100"},"level":{"type":"string","title":"Level","description":"low, moderate, elevated, high"},"components":{"items":{"$ref":"#/components/schemas/RiskScoreComponent"},"type":"array","title":"Components"},"summary":{"type":"string","title":"Summary"},"concerns":{"items":{"type":"string"},"type":"array","title":"Concerns"},"positives":{"items":{"type":"string"},"type":"array","title":"Positives"},"last_updated":{"type":"string","title":"Last Updated"}},"type":"object","required":["score","level","components","summary","concerns","positives","last_updated"],"title":"MacroRiskScoreResponse","description":"Composite macro economic risk score."},"MacroSummaryResponse":{"properties":{"fed_funds_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fed Funds Rate"},"treasury_3m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Treasury 3M"},"treasury_6m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Treasury 6M"},"treasury_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Treasury 1Y"},"treasury_2y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Treasury 2Y"},"treasury_5y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Treasury 5Y"},"treasury_10y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Treasury 10Y"},"treasury_30y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Treasury 30Y"},"rates_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rates Date"},"spread_10y_2y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Spread 10Y 2Y"},"spread_10y_3m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Spread 10Y 3M"},"yield_curve_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Yield Curve Status"},"pce_core_yoy":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pce Core Yoy"},"inflation_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inflation Date"},"margin_debt":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Margin Debt"},"net_margin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Net Margin"},"margin_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Margin Date"},"margin_pct_of_ath":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Margin Pct Of Ath"},"sp500_close":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sp500 Close"},"sp500_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sp500 Date"},"view_refreshed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"View Refreshed At"}},"type":"object","title":"MacroSummaryResponse","description":"Consolidated macro dashboard data from materialized view."},"MarginDebtResponse":{"properties":{"report_date":{"type":"string","format":"date","title":"Report Date"},"margin_debt":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Margin Debt","description":"Total margin debt in millions"},"free_credit_cash":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Credit Cash","description":"Free credit in cash accounts (millions)"},"free_credit_margin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Credit Margin","description":"Free credit in margin accounts (millions)"},"net_margin":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Net Margin","description":"Net margin (debt - free credits)"}},"type":"object","required":["report_date"],"title":"MarginDebtResponse","description":"Margin debt data point."},"MarginDebtSummaryResponse":{"properties":{"current":{"$ref":"#/components/schemas/MarginDebtResponse"},"prior_year":{"anyOf":[{"$ref":"#/components/schemas/MarginDebtResponse"},{"type":"null"}]},"yoy_change_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Yoy Change Pct"},"all_time_high":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"All Time High"},"all_time_high_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"All Time High Date"},"history_months":{"type":"integer","title":"History Months","description":"Months of history available","default":0}},"type":"object","required":["current"],"title":"MarginDebtSummaryResponse","description":"Margin debt summary with YoY comparison."},"MarketBreadthResponse":{"properties":{"calculation_date":{"type":"string","format":"date","title":"Calculation Date"},"total_stocks":{"type":"integer","title":"Total Stocks"},"pct_above_50dma":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pct Above 50Dma"},"pct_above_200dma":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pct Above 200Dma"},"new_52w_highs":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"New 52W Highs"},"new_52w_lows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"New 52W Lows"},"highs_lows_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Highs Lows Ratio"},"advancing":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Advancing"},"declining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Declining"},"advance_decline_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Advance Decline Ratio"}},"type":"object","required":["calculation_date","total_stocks"],"title":"MarketBreadthResponse","description":"Market breadth indicators."},"MarketConcentrationResponse":{"properties":{"calculation_date":{"type":"string","format":"date","title":"Calculation Date"},"total_market_cap_billions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Market Cap Billions"},"total_stocks":{"type":"integer","title":"Total Stocks"},"top5_weight_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top5 Weight Pct"},"top5_tickers":{"anyOf":[{"items":{"$ref":"#/components/schemas/ConcentrationTickerResponse"},"type":"array"},{"type":"null"}],"title":"Top5 Tickers"},"mag7_weight_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mag7 Weight Pct"},"mag7_tickers":{"anyOf":[{"items":{"$ref":"#/components/schemas/ConcentrationTickerResponse"},"type":"array"},{"type":"null"}],"title":"Mag7 Tickers"},"top10_weight_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top10 Weight Pct"},"top10_tickers":{"anyOf":[{"items":{"$ref":"#/components/schemas/ConcentrationTickerResponse"},"type":"array"},{"type":"null"}],"title":"Top10 Tickers"},"hhi_index":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Hhi Index"}},"type":"object","required":["calculation_date","total_stocks"],"title":"MarketConcentrationResponse","description":"Market concentration metrics."},"MarketValuationResponse":{"properties":{"calculation_date":{"type":"string","format":"date","title":"Calculation Date"},"market_pe_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Market Pe Ratio"},"market_forward_pe":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Market Forward Pe"},"market_pb_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Market Pb Ratio"},"market_ps_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Market Ps Ratio"},"median_pe_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Pe Ratio"},"total_market_cap_billions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Market Cap Billions"},"buffett_indicator":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Buffett Indicator"},"stocks_included":{"type":"integer","title":"Stocks Included"}},"type":"object","required":["calculation_date","stocks_included"],"title":"MarketValuationResponse","description":"Market-wide valuation metrics."},"NLScreenerRequest":{"properties":{"query":{"type":"string","maxLength":500,"minLength":3,"title":"Query"},"limit":{"type":"integer","maximum":200.0,"minimum":1.0,"title":"Limit","default":50},"offset":{"type":"integer","minimum":0.0,"title":"Offset","default":0},"sort_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort By"},"sort_order":{"type":"string","pattern":"^(asc|desc)$","title":"Sort Order","default":"desc"}},"type":"object","required":["query"],"title":"NLScreenerRequest","description":"Natural language screener request."},"NLScreenerResponse":{"properties":{"total":{"type":"integer","title":"Total"},"results":{"items":{"$ref":"#/components/schemas/StockResult"},"type":"array","title":"Results"},"filters_applied":{"type":"object","title":"Filters Applied"},"sort_by":{"type":"string","title":"Sort By"},"sort_order":{"type":"string","title":"Sort Order"},"nl_query":{"type":"string","title":"Nl Query"},"interpreted_as":{"type":"string","title":"Interpreted As"},"confidence":{"type":"number","title":"Confidence"},"remaining_queries":{"type":"integer","title":"Remaining Queries"}},"type":"object","required":["total","results","filters_applied","sort_by","sort_order","nl_query","interpreted_as","confidence","remaining_queries"],"title":"NLScreenerResponse","description":"NL screener response with filter transparency."},"PatchPreferencesBody":{"properties":{"country_preference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country Preference","description":"2-char country code (US, UK, IN, ...) or null for Global."}},"type":"object","title":"PatchPreferencesBody","description":"PATCH /users/me body. `null` (or omitted) clears the preference.\n\nValidation is intentionally done in the handler rather than via\n`@field_validator` — the project's custom `validation_exception_handler`\ncannot JSON-serialize Pydantic v2 `ctx.error` that holds a raw\n`ValueError`, so we raise `HTTPException(422)` instead."},"PresetScreen":{"type":"string","enum":["top_value","high_growth","dividend_stocks","momentum_leaders","hidden_gems","defensive","buffett","munger","graham","lynch","greenblatt","oshaughnessy"],"title":"PresetScreen"},"PromptTemplateRequest":{"properties":{"article_type":{"type":"string","title":"Article Type"},"system_prompt":{"type":"string","title":"System Prompt"},"summary_prompt":{"type":"string","title":"Summary Prompt"},"sections":{"items":{"$ref":"#/components/schemas/SectionConfig"},"type":"array","title":"Sections"}},"type":"object","required":["article_type","system_prompt","summary_prompt","sections"],"title":"PromptTemplateRequest","description":"Request to create/update prompt template."},"PromptTemplateResponse":{"properties":{"id":{"type":"integer","title":"Id"},"article_type":{"type":"string","title":"Article Type"},"system_prompt":{"type":"string","title":"System Prompt"},"summary_prompt":{"type":"string","title":"Summary Prompt"},"sections":{"items":{"type":"object"},"type":"array","title":"Sections"},"is_default":{"type":"boolean","title":"Is Default"},"version":{"type":"integer","title":"Version"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["id","article_type","system_prompt","summary_prompt","sections","is_default","version","created_at","updated_at"],"title":"PromptTemplateResponse","description":"Prompt template response."},"RenameWatchlistRequest":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"RenameWatchlistRequest"},"RiskScoreComponent":{"properties":{"name":{"type":"string","title":"Name"},"score":{"type":"number","maximum":100.0,"minimum":0.0,"title":"Score"},"weight":{"type":"number","title":"Weight"},"weighted_score":{"type":"number","title":"Weighted Score"},"status":{"type":"string","title":"Status"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail"}},"type":"object","required":["name","score","weight","weighted_score","status"],"title":"RiskScoreComponent","description":"Individual component of the risk score."},"SP500DataPoint":{"properties":{"date":{"type":"string","title":"Date"},"close":{"type":"number","title":"Close"},"change_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change Pct"}},"type":"object","required":["date","close"],"title":"SP500DataPoint","description":"S&P 500 data point."},"SP500HistoryResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SP500DataPoint"},"type":"array","title":"Data"},"current_price":{"type":"number","title":"Current Price"},"ytd_change_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ytd Change Pct"},"one_year_change_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"One Year Change Pct"},"from_date":{"type":"string","title":"From Date"},"to_date":{"type":"string","title":"To Date"}},"type":"object","required":["data","current_price","from_date","to_date"],"title":"SP500HistoryResponse","description":"S&P 500 historical data."},"ScreenerFilters":{"properties":{"min_composite_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Composite Score"},"max_composite_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Max Composite Score"},"min_valuation_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Valuation Score"},"max_valuation_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Max Valuation Score"},"min_quality_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Quality Score"},"max_quality_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Max Quality Score"},"min_growth_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Growth Score"},"max_growth_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Max Growth Score"},"min_health_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Health Score"},"max_health_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Max Health Score"},"min_momentum_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Min Momentum Score"},"max_momentum_score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Max Momentum Score"},"min_pe_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pe Ratio"},"max_pe_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pe Ratio"},"min_pb_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pb Ratio"},"max_pb_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pb Ratio"},"min_ps_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Ps Ratio"},"max_ps_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Ps Ratio"},"min_peg_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Peg Ratio"},"max_peg_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Peg Ratio"},"min_ev_ebitda":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Ev Ebitda"},"max_ev_ebitda":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Ev Ebitda"},"min_roe":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Roe"},"max_roe":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Roe"},"min_roa":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Roa"},"max_roa":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Roa"},"min_roic":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Roic"},"max_roic":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Roic"},"min_gross_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Gross Margin"},"min_operating_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Operating Margin"},"min_net_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Net Margin"},"min_revenue_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Revenue Growth 1Y"},"max_revenue_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Revenue Growth 1Y"},"min_revenue_growth_3y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Revenue Growth 3Y"},"min_eps_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Eps Growth 1Y"},"max_eps_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Eps Growth 1Y"},"min_eps_growth_3y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Eps Growth 3Y"},"min_current_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Current Ratio"},"max_current_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Current Ratio"},"min_quick_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Quick Ratio"},"min_debt_to_equity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Debt To Equity"},"max_debt_to_equity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Debt To Equity"},"min_interest_coverage":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Interest Coverage"},"min_altman_z_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Altman Z Score"},"min_dividend_yield":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Dividend Yield"},"max_dividend_yield":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Dividend Yield"},"min_payout_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Payout Ratio"},"max_payout_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Payout Ratio"},"min_years_of_dividends":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Years Of Dividends"},"min_market_cap":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Market Cap"},"max_market_cap":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Market Cap"},"market_cap_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Cap Tier"},"min_beta":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Beta"},"max_beta":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Beta"},"min_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price"},"max_price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price"},"sectors":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sectors"},"industries":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Industries"},"exchanges":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exchanges"},"min_price_change_1d":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Change 1D"},"max_price_change_1d":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Change 1D"},"min_price_change_1w":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Change 1W"},"max_price_change_1w":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Change 1W"},"min_price_change_1m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Change 1M"},"max_price_change_1m":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Change 1M"},"min_price_change_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Change 1Y"},"max_price_change_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Change 1Y"},"min_pct_from_52w_high":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pct From 52W High"},"max_pct_from_52w_high":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pct From 52W High"},"min_pct_from_52w_low":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Pct From 52W Low"},"max_pct_from_52w_low":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Pct From 52W Low"},"min_forward_pe":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Forward Pe"},"max_forward_pe":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Forward Pe"},"min_price_fcf":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Price Fcf"},"max_price_fcf":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Price Fcf"},"min_ev_sales":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Ev Sales"},"max_ev_sales":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Ev Sales"},"min_piotroski_score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Min Piotroski Score"},"max_piotroski_score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Piotroski Score"},"min_fcf_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Fcf Margin"},"min_asset_turnover":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Asset Turnover"},"min_fcf_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Fcf Growth 1Y"},"max_fcf_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Fcf Growth 1Y"},"min_dividend_growth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Dividend Growth"},"min_book_value_growth":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Book Value Growth"},"min_cash_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Cash Ratio"},"max_debt_to_ebitda":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Debt To Ebitda"},"max_net_debt_to_ebitda":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Net Debt To Ebitda"},"min_volatility_60d":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Volatility 60D"},"max_volatility_60d":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Volatility 60D"},"max_value_trap_risk":{"anyOf":[{"type":"string","pattern":"^(Low|Medium|High)$"},{"type":"null"}],"title":"Max Value Trap Risk"},"exclude_negative_pe":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Exclude Negative Pe"}},"type":"object","title":"ScreenerFilters","description":"Screener filter criteria."},"ScreenerRequest":{"properties":{"filters":{"$ref":"#/components/schemas/ScreenerFilters"},"sort_by":{"type":"string","title":"Sort By","default":"composite_score"},"sort_order":{"type":"string","pattern":"^(asc|desc)$","title":"Sort Order","default":"desc"},"limit":{"type":"integer","maximum":200.0,"minimum":1.0,"title":"Limit","default":50},"offset":{"type":"integer","minimum":0.0,"title":"Offset","default":0}},"type":"object","title":"ScreenerRequest","description":"Full screener request with filters and pagination."},"SectionConfig":{"properties":{"heading":{"type":"string","title":"Heading"},"prompt":{"type":"string","title":"Prompt"},"max_words":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Words"},"format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Format"}},"type":"object","required":["heading","prompt"],"title":"SectionConfig","description":"Section configuration."},"SectorValuationResponse":{"properties":{"sector":{"type":"string","title":"Sector"},"sector_pe_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sector Pe Ratio"},"sector_pb_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sector Pb Ratio"},"sector_ps_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sector Ps Ratio"},"sector_weight":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Sector Weight"},"stocks_in_sector":{"type":"integer","title":"Stocks In Sector"},"pe_percentile":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pe Percentile"}},"type":"object","required":["sector","stocks_in_sector"],"title":"SectorValuationResponse","description":"Sector valuation data."},"SpecialOccasionCreate":{"properties":{"name":{"type":"string","title":"Name"},"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"type":"string","format":"date","title":"End Date"},"gradient_colors":{"type":"string","title":"Gradient Colors"},"is_active":{"type":"boolean","title":"Is Active","default":true}},"type":"object","required":["name","start_date","end_date","gradient_colors"],"title":"SpecialOccasionCreate"},"SpecialOccasionResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"start_date":{"type":"string","format":"date","title":"Start Date"},"end_date":{"type":"string","format":"date","title":"End Date"},"gradient_colors":{"type":"string","title":"Gradient Colors"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","start_date","end_date","gradient_colors","is_active","created_at","updated_at"],"title":"SpecialOccasionResponse"},"SpecialOccasionUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"start_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Start Date"},"end_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"End Date"},"gradient_colors":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gradient Colors"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"type":"object","title":"SpecialOccasionUpdate"},"StockResult":{"properties":{"ticker":{"type":"string","title":"Ticker"},"name":{"type":"string","title":"Name"},"sector":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sector"},"industry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Industry"},"exchange":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Exchange"},"market_cap":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Market Cap"},"market_cap_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market Cap Tier"},"price":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price"},"price_change_1d_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Price Change 1D Pct"},"composite_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Composite Score"},"valuation_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Valuation Score"},"quality_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Quality Score"},"growth_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Growth Score"},"health_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Health Score"},"momentum_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Momentum Score"},"pe_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pe Ratio"},"pb_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pb Ratio"},"ps_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ps Ratio"},"peg_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Peg Ratio"},"ev_ebitda":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ev Ebitda"},"dividend_yield":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Dividend Yield"},"payout_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Payout Ratio"},"beta":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Beta"},"roe":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Roe"},"roa":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Roa"},"roic":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Roic"},"gross_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gross Margin"},"operating_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Operating Margin"},"net_margin":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Net Margin"},"revenue_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Revenue Growth 1Y"},"eps_growth_1y":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eps Growth 1Y"},"current_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Current Ratio"},"debt_to_equity":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Debt To Equity"}},"type":"object","required":["ticker","name","sector","industry","market_cap","market_cap_tier","price","price_change_1d_pct","composite_score","valuation_score","quality_score","growth_score","health_score","momentum_score","pe_ratio","pb_ratio","ps_ratio","peg_ratio","ev_ebitda","dividend_yield","payout_ratio","beta","roe","roa","roic","gross_margin","operating_margin","net_margin","revenue_growth_1y","eps_growth_1y","current_ratio","debt_to_equity"],"title":"StockResult","description":"Individual stock result with comprehensive metrics."},"StripeEventPayload":{"properties":{"event_type":{"type":"string","title":"Event Type"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id"},"stripe_subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Subscription Id"},"stripe_payment_intent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Payment Intent Id"},"period_start":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period Start"},"period_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period End"},"metadata":{"type":"object","title":"Metadata","default":{}}},"type":"object","required":["event_type"],"title":"StripeEventPayload","description":"Stripe event forwarded from Next.js webhook."},"Token":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type"}},"type":"object","required":["access_token","token_type"],"title":"Token","description":"Token response model."},"TreasuryYieldResponse":{"properties":{"maturity":{"type":"string","title":"Maturity"},"rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rate"},"date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date"}},"type":"object","required":["maturity"],"title":"TreasuryYieldResponse","description":"Treasury yield data."},"UpdateCreditCostRequest":{"properties":{"credit_cost":{"type":"integer","maximum":1000.0,"minimum":0.0,"title":"Credit Cost"},"display_name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Display Name"}},"type":"object","required":["credit_cost"],"title":"UpdateCreditCostRequest"},"UpdatePortfolioRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Name"},"holdings":{"items":{"$ref":"#/components/schemas/HoldingInput"},"type":"array","title":"Holdings"},"expected_version":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Expected Version"}},"type":"object","required":["holdings"],"title":"UpdatePortfolioRequest"},"UpdateTickersRequest":{"properties":{"tickers":{"items":{"type":"string"},"type":"array","title":"Tickers"}},"type":"object","required":["tickers"],"title":"UpdateTickersRequest","description":"Request to manually update article tickers."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"YieldSpreadResponse":{"properties":{"name":{"type":"string","title":"Name"},"spread":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Spread"},"is_inverted":{"type":"boolean","title":"Is Inverted","default":false}},"type":"object","required":["name"],"title":"YieldSpreadResponse","description":"Yield curve spread."}},"securitySchemes":{"HTTPBasic":{"type":"http","scheme":"basic"},"HTTPBearer":{"type":"http","scheme":"bearer"}}}}