{"openapi":"3.1.0","info":{"title":"Fahali Intelligence API","version":"1.0.0","description":"Structured market intelligence endpoints for AI agents, MCP tools, and institutional consumers. All responses conform to the canonical Fahali Intelligence schema family. Observation, not financial advice — every surface carries this disclaimer."},"servers":[{"url":"https://app.fahaliai.com","description":"Production"},{"url":"http://localhost:5000","description":"Local development"}],"paths":{"/api/market/movers":{"get":{"summary":"Top market movers by detection activity","description":"Returns the top 25 symbols ranked by alert frequency over the last 24 hours. No authentication required.","operationId":"getMarketMovers","responses":{"200":{"description":"Top movers list","content":{"application/json":{"schema":{"type":"object","properties":{"movers":{"type":"array","items":{"type":"object","properties":{"symbol":{"type":"string"},"alertCount":{"type":"integer"},"avgConfidence":{"type":"number"},"lastAlert":{"type":"string","format":"date-time"}}}},"asOf":{"type":"string","format":"date-time"}}}}}}}}},"/api/public/stats":{"get":{"summary":"Live platform stats (public)","description":"Real-time coverage: instruments monitored, detections in last 24h, last detection time. No authentication. Returns no engine count by design — the per-engine record is at /api/track-record/engines.","operationId":"getPublicStats","responses":{"200":{"description":"Live stats","content":{"application/json":{"schema":{"type":"object","properties":{"instrumentsMonitored":{"type":"integer"},"detections24h":{"type":"integer"},"lastDetectionAt":{"type":"string","format":"date-time"},"asOf":{"type":"string","format":"date-time"}}}}}}}}},"/api/institutional/signals":{"get":{"summary":"Detection signals feed (public)","description":"Recent detection signals with engine, direction/phase, confidence, and judged outcome fields. Asset-balanced (crypto + US equities/ETFs). No authentication.","operationId":"getInstitutionalSignals","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string"},"description":"Exact symbol filter (e.g. BTCUSDT). Queries the DB directly."},{"name":"asset","in":"query","required":false,"schema":{"type":"string","enum":["crypto","equity"]},"description":"Asset-class filter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"},"description":"Cap results."}],"responses":{"200":{"description":"Signals list","content":{"application/json":{"schema":{"type":"object","properties":{"signals":{"type":"array","items":{"type":"object"}},"count":{"type":"integer"},"timestamp":{"type":"integer"}}}}}}}}},"/api/alerts":{"get":{"summary":"Recent alerts (public)","description":"Recent detection alerts with verdicts. Optional symbol filter. No authentication.","operationId":"getAlerts","parameters":[{"name":"symbol","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Alerts list","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/engines/status":{"get":{"summary":"Engine liveness (public)","description":"Per-engine status across the 18 canonical engines: last fired, 1h/24h/7d counts, and a firing/active/quiet/dormant status (event-gated engines are quiet by design). Includes market-session context. No authentication.","operationId":"getEngineStatus","responses":{"200":{"description":"Engine status","content":{"application/json":{"schema":{"type":"object","properties":{"engines":{"type":"array","items":{"type":"object"}},"market_context":{"type":"object"},"asof":{"type":"string","format":"date-time"}}}}}}}}},"/api/case-studies":{"get":{"summary":"Track record — predicted vs. outcome (public)","description":"Verified detections with the forecast made, the realized outcome (direction/magnitude correct or not), and entry/horizon prices. Append-only; includes misses. No authentication.","operationId":"getCaseStudies","responses":{"200":{"description":"Case studies","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/track-record/scorecard":{"get":{"summary":"Accuracy scorecard with base-rate lift (public)","description":"Direction / magnitude / crash-catch axes measured as lift over base rate (not a vanity win-rate). No authentication.","operationId":"getScorecard","responses":{"200":{"description":"Scorecard","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/billing/checkout":{"post":{"summary":"Create a Stripe checkout session","description":"Starts a subscription checkout for a pricing tier. Requires authentication (Firebase ID token as Bearer). Returns a Stripe-hosted checkout URL.","operationId":"createCheckout","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tier":{"type":"string","enum":["retail","professional","elite","institutional","enterprise"]}},"required":["tier"]}}}},"responses":{"200":{"description":"Checkout session","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}},"401":{"description":"Authentication required"}}}},"/agent/verdict":{"get":{"summary":"Get structured market verdict","description":"Returns direction (bullish/bearish/neutral), confidence score, reasoning chain, expected move percentage, and forecast horizon for one or more symbols. Optionally includes contagion risk data.","operationId":"getMarketVerdict","parameters":[{"name":"symbols","in":"query","description":"Comma-separated trading symbols (e.g. 'BTCUSDT,ETHUSDT'). Omitting returns top signals across all symbols.","required":false,"schema":{"type":"string"}},{"name":"includeContagion","in":"query","description":"If true, enriches response with contagion risk from tail_dependence table.","required":false,"schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Market verdict intelligence","headers":{"X-Fahali-Direction-Confidence":{"schema":{"type":"integer","enum":[1]}},"X-Fahali-Schema-Version":{"schema":{"type":"string","enum":["1.0"]}},"X-Fahali-Contagion-Included":{"schema":{"type":"integer","enum":[0,1]}}},"content":{"application/json":{"schema":{"type":"object","properties":{"schemaVersion":{"type":"string","enum":["1.0"]},"updatedAt":{"type":"string","format":"date-time"},"count":{"type":"integer"},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpectraIntelligence"}}}}}}},"503":{"description":"Database not ready","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/agent/portfolio-risk":{"get":{"summary":"Get portfolio risk assessment","description":"Returns overall risk score, value-at-risk, expected drawdown, per-position risk breakdown, and contagion risk. Requires connected exchange accounts for personalized data.","operationId":"getPortfolioRisk","parameters":[],"responses":{"200":{"description":"Portfolio risk assessment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpectraPortfolioRiskAssessment"}}}}}}},"/agent/capital-flow":{"get":{"summary":"Get capital flow intelligence","description":"Returns net flow USD, direction (inflow/outflow/neutral), institutional vs retail breakdown, whale activity, and flow trend for a specific symbol.","operationId":"getCapitalFlow","parameters":[{"name":"symbol","in":"query","description":"Trading symbol (e.g. 'BTCUSDT'). Required.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Capital flow intelligence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpectraCapitalFlowResponse"}}}},"400":{"description":"Missing symbol parameter","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/agent/contagion":{"get":{"summary":"Get contagion map","description":"Returns cross-asset contagion and tail dependence map: nodes (symbols with risk scores), edges (pairwise correlation strength), and clusters of correlated assets.","operationId":"getContagionMap","parameters":[],"responses":{"200":{"description":"Contagion map","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpectraContagionMap"}}}}}}},"/agent/daily-brief":{"get":{"summary":"Get daily market intelligence brief","description":"Returns a yesterday-vs-today diff: alert volume change, critical alerts, current market regime, and prior intel post reference. Free tier returns regime + headline; Professional tier gets full delta with prior-period comparison. Sources: alerts, agent_events, spectra_intel_posts. Observation, not financial advice.","operationId":"getDailyBrief","parameters":[],"responses":{"200":{"description":"Daily brief","content":{"application/json":{"schema":{"type":"object","properties":{"as_of":{"type":"string","format":"date-time"},"since":{"type":"string","format":"date-time"},"alert_activity":{"type":"object","properties":{"new_alerts_24h":{"type":"integer"},"prior_24h":{"type":"integer"},"change":{"type":"integer"},"critical_alerts":{"type":"integer"},"symbols_affected":{"type":"integer"}}},"regime":{"type":"object","properties":{"regime":{"type":"string"},"confidence":{"type":"number"},"as_of":{"type":"string","format":"date-time"}},"nullable":true},"prior_intel":{"type":"object","properties":{"slug":{"type":"string"},"claim":{"type":"string"},"published_at":{"type":"string","format":"date-time"}},"nullable":true},"note":{"type":"string"}}}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Firebase ID token (logged-in user) for billing and portfolio endpoints."}},"schemas":{"SpectraDirection":{"type":"string","enum":["bullish","bearish","neutral","unknown"]},"SpectraSeverity":{"type":"string","enum":["critical","high","moderate","low"]},"SpectraRiskLevel":{"type":"string","enum":["critical","high","moderate","low"]},"SpectraActionType":{"type":"string","enum":["hold","reduce","increase","exit","hedge","watch"]},"SpectraVerdict":{"type":"object","properties":{"direction":{"$ref":"#/components/schemas/SpectraDirection"},"confidence":{"type":"number","minimum":0,"maximum":1},"uncertainty":{"type":"number","minimum":0,"maximum":1},"expectedMovePct":{"type":"number","nullable":true},"forecastHorizon":{"type":"string","enum":["12h","24h","72h","7d","30d"]},"severity":{"$ref":"#/components/schemas/SpectraSeverity"},"urgencyScore":{"type":"number","minimum":0,"maximum":1}},"required":["direction","confidence","uncertainty","forecastHorizon","severity","urgencyScore"]},"SpectraReasoning":{"type":"object","properties":{"steps":{"type":"array","items":{"type":"string"}},"toolsUsed":{"type":"array","items":{"type":"string"}},"conflictScore":{"type":"number","minimum":0,"maximum":1},"missingSignals":{"type":"array","items":{"type":"string"}},"cycleCount":{"type":"integer","minimum":1}},"required":["steps","toolsUsed","conflictScore","missingSignals","cycleCount"]},"SpectraCapitalFlow":{"type":"object","properties":{"netFlowUsd":{"type":"number"},"direction":{"type":"string","enum":["inflow","outflow","neutral"]},"confidence":{"type":"number"},"institutionalRatio":{"type":"number"},"whaleCount":{"type":"integer"},"trend":{"type":"string","enum":["accelerating","decelerating","stable"]}},"required":["netFlowUsd","direction","confidence","institutionalRatio","whaleCount","trend"]},"SpectraContagion":{"type":"object","properties":{"risk":{"$ref":"#/components/schemas/SpectraRiskLevel"},"confidence":{"type":"number"},"affectedSymbols":{"type":"array","items":{"type":"object","properties":{"symbol":{"type":"string"},"correlation":{"type":"number"},"expectedImpactPct":{"type":"number"},"timeToMaterializeHours":{"type":"number"}}}}},"required":["risk","confidence","affectedSymbols"]},"SpectraAction":{"type":"object","properties":{"type":{"$ref":"#/components/schemas/SpectraActionType"},"targetExposure":{"type":"number","nullable":true},"timeframe":{"type":"string","enum":["immediate","24h","72h","7d"]},"rationale":{"type":"string"}},"required":["type","timeframe","rationale"]},"SpectraProvenance":{"type":"object","properties":{"source":{"type":"string","enum":["predictions","alerts","agent_verdict","derived"]},"modelVersion":{"type":"string"},"engineNames":{"type":"array","items":{"type":"string"}},"walkForwardValidated":{"type":"boolean"},"dataAsOf":{"type":"string","format":"date-time"}},"required":["source","modelVersion","engineNames","walkForwardValidated","dataAsOf"]},"SpectraAiMetadata":{"type":"object","properties":{"schemaVersion":{"type":"string","enum":["1.0"]},"reasoningTrace":{"type":"boolean"},"confidenceNormalized":{"type":"boolean"},"schemaStable":{"type":"boolean"},"lastModelRetrain":{"type":"string","format":"date","nullable":true}},"required":["schemaVersion","reasoningTrace","confidenceNormalized","schemaStable"]},"SpectraIntelligence":{"type":"object","properties":{"symbol":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"verdict":{"$ref":"#/components/schemas/SpectraVerdict"},"reasoning":{"$ref":"#/components/schemas/SpectraReasoning"},"capitalFlow":{"$ref":"#/components/schemas/SpectraCapitalFlow"},"contagion":{"$ref":"#/components/schemas/SpectraContagion"},"action":{"$ref":"#/components/schemas/SpectraAction"},"provenance":{"$ref":"#/components/schemas/SpectraProvenance"},"aiMetadata":{"$ref":"#/components/schemas/SpectraAiMetadata"}},"required":["symbol","timestamp","verdict","reasoning","provenance","aiMetadata"]},"SpectraPortfolioRiskAssessment":{"type":"object","properties":{"portfolio":{"type":"object","properties":{"totalValue":{"type":"number"},"overallRiskScore":{"type":"number"},"overallRiskLevel":{"$ref":"#/components/schemas/SpectraRiskLevel"},"expectedDrawdownPct":{"type":["number","null"],"description":"Expected shortfall at 95%: the mean loss across the worst 5% of observations in the window, percent, positive for a loss. Historical measurement over the book's own return distribution, NOT a forecast. Null when unmeasurable — read riskMetricsBasis.reason."},"valueAtRisk95":{"type":["number","null"],"description":"Historical Value-at-Risk at 95% in currency, positive for a loss: on the worst 1 day in 20 of the window, the book lost at least this much. Historical measurement, NOT a forecast. Null when unmeasurable."},"riskMetricsBasis":{"type":"object","description":"How the drawdown and VaR figures were produced, or why they are absent.","properties":{"method":{"type":"string","enum":["historical_simulation","unmeasured"]},"reason":{"type":"string"},"observations":{"type":"integer"},"coveredWeightPct":{"type":"number","description":"Share of book weight with usable price history. The estimate treats this subset as representative; below 60% it abstains."},"uncoveredSymbols":{"type":"array","items":{"type":"string"}},"varLevel":{"type":"number"},"positionAligned":{"type":"boolean","description":"True when series were aligned by position rather than bar timestamp — a weaker basis."}},"required":["method"]}},"required":["totalValue","overallRiskScore","overallRiskLevel","expectedDrawdownPct","valueAtRisk95"]},"positions":{"type":"array","items":{"type":"object","properties":{"symbol":{"type":"string"},"allocation":{"type":"number"},"riskScore":{"type":"number"},"riskLevel":{"$ref":"#/components/schemas/SpectraRiskLevel"},"unrealizedPnlPct":{"type":"number","description":"P&L since entry, percent. Historical and already realized — NOT a forecast. Renamed 2026-08-06 from `expectedMovePct`, a forward-looking name that misrepresented this backward-looking figure."},"correlationToPortfolio":{"type":["number","null"],"description":"Not computed. Always null — never fabricated (2026-07-20)."},"recommendation":{"type":"object","properties":{"action":{"$ref":"#/components/schemas/SpectraActionType"},"rationale":{"type":"string"}},"required":["action","rationale"]}},"required":["symbol","allocation","riskScore","riskLevel","unrealizedPnlPct","correlationToPortfolio","recommendation"],"description":"Zero-allocation holdings are excluded before this array is built — a risk system must not score or recommend on an asset the user does not own."}},"analysisStatus":{"type":"object","description":"Reconciliation between the VaR/drawdown coverage figure and the uncovered-symbol list. PARTIAL when coveredWeightPct reads near-complete while symbols still lack price history, or when the risk metrics are unmeasured outright.","properties":{"status":{"type":"string","enum":["OK","PARTIAL"]},"reason":{"type":"string"}},"required":["status"]},"contagionRisk":{"type":"object","properties":{"highestRiskSymbol":{"type":"string"},"affectedCount":{"type":"integer"},"expectedPortfolioImpactPct":{"type":["number","null"],"description":"Magnitude of the estimated portfolio move, percent, measured as a beta-weighted response to the shock asset's own empirical lower-tail return. Null when it cannot be measured for this book — read basis.reason. Never 0 as a stand-in for unknown."},"basis":{"type":"object","description":"How the estimate was produced, or why it is absent.","properties":{"method":{"type":"string","enum":["beta_weighted_empirical_tail","unmeasured"]},"reason":{"type":"string"},"shockSymbol":{"type":"string"},"shockPct":{"type":["number","null"],"description":"Measured lower-tail move of the shock asset, percent."},"portfolioMovePct":{"type":["number","null"],"description":"Signed portfolio move. Negative is adverse; positive means the book hedges the shock."},"portfolioBeta":{"type":["number","null"]},"coveredWeightPct":{"type":"number"},"tailPercentile":{"type":"number"}},"required":["method"]}},"required":["highestRiskSymbol","affectedCount","expectedPortfolioImpactPct"]},"provenance":{"$ref":"#/components/schemas/SpectraProvenance"},"aiMetadata":{"$ref":"#/components/schemas/SpectraAiMetadata"}},"required":["portfolio","positions","analysisStatus","contagionRisk","provenance","aiMetadata"]},"SpectraContagionMap":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object","properties":{"symbol":{"type":"string"},"riskScore":{"type":"number"},"riskLevel":{"$ref":"#/components/schemas/SpectraRiskLevel"},"confidence":{"type":"number"}},"required":["symbol","riskScore","riskLevel","confidence"]}},"edges":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string"},"target":{"type":"string"},"strength":{"type":"number"},"correlation":{"type":"number"},"confidence":{"type":"number"},"severity":{"type":"string","description":"Derived from the edge's own measured strength (tail_correlation), never carried through from the upstream engine's contagion_risk label. Edges below a 0.1 materiality floor are not emitted at all (see server/lib/contagionGraph.ts classifyEdgeSeverity).","enum":["low","moderate","high","extreme"]},"lagHours":{"type":["number","null"],"description":"tail_dependence has no lag column. Always null today; never a fabricated constant."},"sampleSize":{"type":"integer","description":"How many times this (source, target) pair was independently re-observed within the endpoint's 1-hour lookback -- NOT a statistical sample size for the correlation coefficient itself, which tail_dependence does not expose."}},"required":["source","target","strength","correlation","confidence","severity","lagHours","sampleSize"]}},"clusters":{"type":"array","items":{"type":"object","properties":{"symbols":{"type":"array","items":{"type":"string"}},"riskLevel":{"$ref":"#/components/schemas/SpectraRiskLevel"},"leadSymbol":{"type":"string","description":"Absent unless a directed edge into this cluster has a strict out-degree winner AND that winner's out-degree exceeds the runner-up's by at least 20% (a 1-edge margin over a large base is not treated as confident). Never alphabetical, never symbols[0]."},"leadOutDegree":{"type":"integer","description":"Present whenever the cluster has at least one directed edge, regardless of whether the margin was enough to claim leadSymbol -- lets a consumer see a thin-margin case for what it is."},"runnerUpOutDegree":{"type":"integer","description":"Present whenever there is a second out-degree candidate to compare against. Absent when leadOutDegree has no rival (a lone directed edge)."},"lagHours":{"type":"number","description":"Absent unless at least one edge from the lead carries an observed lag. tail_dependence has no lag column today, so this is always absent."},"edgeCount":{"type":"integer"}},"required":["symbols","riskLevel","edgeCount"]}},"provenance":{"$ref":"#/components/schemas/SpectraProvenance"},"aiMetadata":{"$ref":"#/components/schemas/SpectraAiMetadata"}},"required":["nodes","edges","clusters","provenance","aiMetadata"]},"SpectraCapitalFlowResponse":{"type":"object","properties":{"symbol":{"type":"string"},"windowHours":{"type":"integer"},"netFlowUsd":{"type":"number"},"direction":{"type":"string","enum":["inflow","outflow","neutral"]},"confidence":{"type":"number"},"breakdown":{"type":"object","properties":{"institutional":{"type":"number"},"retail":{"type":"number"},"whale":{"type":"number"}},"required":["institutional","retail","whale"]},"trend":{"type":"string","enum":["accelerating","decelerating","stable"]},"provenance":{"$ref":"#/components/schemas/SpectraProvenance"},"aiMetadata":{"$ref":"#/components/schemas/SpectraAiMetadata"}},"required":["symbol","windowHours","netFlowUsd","direction","confidence","breakdown","trend","provenance","aiMetadata"]}}}}