# API Documentation ## Overview Vault Dashboard exposes a small read-only HTTP API plus a WebSocket stream. Base capabilities: - health monitoring - portfolio snapshot retrieval - options chain retrieval - strategy analysis retrieval - periodic real-time portfolio updates over WebSocket Unless noted otherwise, all responses are JSON. --- ## Conventions ### Base URL Examples: ```text http://localhost:8000 https://vault.example.com ``` ### Content type Responses use: ```http Content-Type: application/json ``` ### Authentication There is currently **no application-layer authentication** on these endpoints. If the deployment requires restricted access, enforce it at the network or reverse-proxy layer. ### Errors The app currently relies mostly on framework defaults. Typical failures may include: - `422 Unprocessable Entity` for invalid query parameters - `500 Internal Server Error` for unexpected runtime issues --- ## HTTP endpoints ## 1. Health ### `GET /health` Deployment and uptime check. #### Query parameters None. #### Response schema ```json { "status": "ok", "environment": "production", "redis_enabled": false } ``` #### Field definitions - `status` (`string`): expected value is currently `"ok"` - `environment` (`string`): runtime environment from `APP_ENV` or `ENVIRONMENT` - `redis_enabled` (`boolean`): `true` when Redis is configured and connected #### Example request ```bash curl -fsS http://localhost:8000/health ``` #### Example response ```json { "status": "ok", "environment": "development", "redis_enabled": false } ``` --- ## 2. Portfolio ### `GET /api/portfolio` Returns a portfolio snapshot derived from the current quote for a symbol. #### Query parameters | Name | Type | Required | Default | Description | |---|---|---:|---|---| | `symbol` | string | no | `GLD` | Ticker symbol to analyze | #### Response schema ```json { "symbol": "GLD", "spot_price": 215.0, "portfolio_value": 215000.0, "loan_amount": 600000.0, "ltv_ratio": 2.7907, "updated_at": "2026-03-21T12:34:56.000000+00:00", "source": "fallback" } ``` #### Field definitions - `symbol` (`string`): requested ticker, uppercased - `spot_price` (`number`): latest spot/quote price - `portfolio_value` (`number`): current modeled collateral value, currently `spot_price * 1000` - `loan_amount` (`number`): modeled loan balance, currently fixed at `600000.0` - `ltv_ratio` (`number`): `loan_amount / portfolio_value` - `updated_at` (`string`, ISO 8601): response generation timestamp - `source` (`string`): quote source such as `yfinance` or `fallback` #### Example request ```bash curl "http://localhost:8000/api/portfolio?symbol=GLD" ``` #### Example response ```json { "symbol": "GLD", "spot_price": 215.0, "portfolio_value": 215000.0, "loan_amount": 600000.0, "ltv_ratio": 2.7907, "updated_at": "2026-03-21T12:34:56.000000+00:00", "source": "fallback" } ``` --- ## 3. Options chain ### `GET /api/options` Returns a simplified options chain snapshot for the symbol. #### Query parameters | Name | Type | Required | Default | Description | |---|---|---:|---|---| | `symbol` | string | no | `GLD` | Ticker symbol to analyze | #### Response schema ```json { "symbol": "GLD", "updated_at": "2026-03-21T12:34:56.000000+00:00", "calls": [ { "strike": 225.75, "premium": 6.45, "expiry": "2026-06-19" } ], "puts": [ { "strike": 204.25, "premium": 6.02, "expiry": "2026-06-19" } ], "source": "fallback" } ``` #### Array item schema Each option row in `calls` or `puts` has: - `strike` (`number`) - `premium` (`number`) - `expiry` (`string`, `YYYY-MM-DD`) #### Field definitions - `symbol` (`string`): requested ticker, uppercased - `updated_at` (`string`, ISO 8601): response generation timestamp - `calls` (`array`): example call rows derived from spot - `puts` (`array`): example put rows derived from spot - `source` (`string`): upstream quote source used to derive the chain #### Notes The current options chain is synthetic. It is not yet a full broker-grade chain feed. #### Example request ```bash curl "http://localhost:8000/api/options?symbol=GLD" ``` --- ## 4. Strategies ### `GET /api/strategies` Returns strategy comparison data, recommendations by risk profile, and sensitivity analysis. #### Query parameters | Name | Type | Required | Default | Description | |---|---|---:|---|---| | `symbol` | string | no | `GLD` | Ticker symbol to analyze | #### Top-level response schema ```json { "symbol": "GLD", "updated_at": "2026-03-21T12:34:56.000000+00:00", "paper_parameters": {}, "strategies": [], "recommendations": {}, "sensitivity_analysis": {} } ``` #### Top-level field definitions - `symbol` (`string`): requested ticker, uppercased - `updated_at` (`string`, ISO 8601): response generation timestamp - `paper_parameters` (`object`): engine inputs used for the analysis - `strategies` (`array`): detailed strategy comparison rows - `recommendations` (`object`): recommendation results keyed by risk profile - `sensitivity_analysis` (`object`): recommendation changes across parameter shifts ### 4.1 `paper_parameters` schema ```json { "portfolio_value": 1000000.0, "loan_amount": 600000.0, "margin_call_threshold": 0.75, "spot_price": 460.0, "volatility": 0.16, "risk_free_rate": 0.045 } ``` Fields: - `portfolio_value` (`number`) - `loan_amount` (`number`) - `margin_call_threshold` (`number`) - `spot_price` (`number`) - `volatility` (`number`) - `risk_free_rate` (`number`) ### 4.2 `strategies[]` schema Each element in `strategies` is produced by `StrategySelectionEngine.compare_all_strategies()`: ```json { "name": "protective_put_atm", "cost": {}, "protection": {}, "scenarios": [], "score_inputs": { "annual_cost": 0.0, "hedged_ltv_at_threshold": 0.0 } } ``` Fields: - `name` (`string`): internal strategy identifier - `cost` (`object`): strategy-specific cost payload - `protection` (`object`): strategy-specific protection payload - `scenarios` (`array`): scenario analysis rows - `score_inputs` (`object`): normalized inputs used for recommendation scoring #### Protective put cost schema Typical `cost` object for `protective_put_*`: ```json { "strategy": "protective_put_atm", "label": "ATM", "strike": 460.0, "strike_pct": 1.0, "premium_per_share": 21.1234, "total_cost": 45920.43, "cost_pct_of_portfolio": 0.04592, "term_months": 12, "annualized_cost": 45920.43, "annualized_cost_pct": 0.04592 } ``` #### Protective put protection schema ```json { "strategy": "protective_put_atm", "threshold_price": 368.0, "strike": 460.0, "portfolio_floor_value": 1000000.0, "unhedged_ltv_at_threshold": 0.75, "hedged_ltv_at_threshold": 0.652174, "payoff_at_threshold": 200000.0, "maintains_margin_call_buffer": true } ``` #### Protective put scenario row schema ```json { "price_change_pct": -0.2, "gld_price": 368.0, "gold_value": 800000.0, "option_payoff": 200000.0, "hedge_cost": 45920.43, "net_portfolio_value": 954079.57, "unhedged_ltv": 0.75, "hedged_ltv": 0.6, "margin_call_without_hedge": true, "margin_call_with_hedge": false } ``` #### Laddered put cost schema Typical `cost` object for `laddered_put_*`: ```json { "strategy": "laddered_put_50_50_atm_otm95", "label": "50_50_ATM_OTM95", "legs": [ { "weight": 0.5, "strike": 460.0, "premium_per_share": 21.1234, "weighted_cost": 22960.22 } ], "blended_premium_per_share": 18.4567, "blended_cost": 40123.45, "cost_pct_of_portfolio": 0.040123, "annualized_cost": 40123.45, "annualized_cost_pct": 0.040123 } ``` #### Laddered put protection schema ```json { "strategy": "laddered_put_50_50_atm_otm95", "threshold_price": 368.0, "portfolio_floor_value": 975000.0, "payoff_at_threshold": 175000.0, "unhedged_ltv_at_threshold": 0.75, "hedged_ltv_at_threshold": 0.615385, "maintains_margin_call_buffer": true, "legs": [ { "weight": 0.5, "strike": 460.0, "weighted_payoff_at_threshold": 100000.0 } ] } ``` #### Lease duration analysis cost schema Typical `cost` object for `lease_duration_analysis`: ```json { "strategy": "lease_duration_analysis", "comparison": [ { "months": 3, "strike": 460.0, "premium_per_share": 9.1234, "total_cost": 19833.48, "annualized_cost": 79333.92, "annualized_cost_pct": 0.079334, "rolls_per_year": 4.0, "recommended_roll_month": 2 } ], "optimal_duration_months": 12, "lowest_annual_cost": 45920.43, "lowest_annual_cost_pct": 0.04592 } ``` #### Lease duration analysis protection schema ```json { "strategy": "lease_duration_analysis", "threshold_price": 368.0, "durations": [ { "months": 12, "payoff_at_threshold": 200000.0, "hedged_ltv_at_threshold": 0.6, "maintains_margin_call_buffer": true } ] } ``` ### 4.3 `recommendations` schema The object contains keys: - `conservative` - `balanced` - `cost_sensitive` Each recommendation object has this shape: ```json { "risk_profile": "balanced", "recommended_strategy": "laddered_put_50_50_atm_otm95", "rationale": { "portfolio_value": 1000000.0, "loan_amount": 600000.0, "margin_call_threshold": 0.75, "spot_price": 460.0, "volatility": 0.16, "risk_free_rate": 0.045 }, "comparison_summary": [ { "name": "protective_put_atm", "annual_cost": 45920.43, "hedged_ltv_at_threshold": 0.6 } ] } ``` ### 4.4 `sensitivity_analysis` schema ```json { "volatility": [ { "volatility": 0.12, "recommended_strategy": "protective_put_otm_95" } ], "spot_price": [ { "spot_price": 414.0, "recommended_strategy": "protective_put_otm_95" } ] } ``` --- ## WebSocket API ## Endpoint ### `WS /ws/updates` Used for server-pushed real-time updates. ### Connection lifecycle 1. Client opens a WebSocket connection to `/ws/updates` 2. Server accepts the connection 3. Server immediately sends a `connected` event 4. Server periodically broadcasts `portfolio_update` events 5. Client may keep the connection alive by sending text frames 6. Server removes the connection when disconnected or on send failure ### Event: `connected` Sent once after successful connection. #### Schema ```json { "type": "connected", "message": "Real-time updates enabled" } ``` Fields: - `type` (`string`): event name - `message` (`string`): human-readable confirmation ### Event: `portfolio_update` Broadcast on an interval controlled by `WEBSOCKET_INTERVAL_SECONDS`. #### Schema ```json { "type": "portfolio_update", "connections": 2, "portfolio": { "symbol": "GLD", "spot_price": 215.0, "portfolio_value": 215000.0, "loan_amount": 600000.0, "ltv_ratio": 2.7907, "updated_at": "2026-03-21T12:34:56.000000+00:00", "source": "fallback" } } ``` Fields: - `type` (`string`): event name - `connections` (`integer`): current number of connected WebSocket clients - `portfolio` (`object`): same schema as `GET /api/portfolio` ### Example JavaScript client ```js const ws = new WebSocket('ws://localhost:8000/ws/updates'); ws.onmessage = (event) => { const payload = JSON.parse(event.data); console.log(payload.type, payload); }; ws.onopen = () => { // optional keepalive or ping surrogate setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.send('ping'); } }, 10000); }; ``` --- ## OpenAPI Because the app is built on FastAPI, interactive docs are typically available at: - `/docs` - `/redoc` This file is the human-oriented reference for payload semantics and current behavior. ## Notes and limitations - Endpoints are read-only today - There are no POST/PUT/DELETE endpoints yet - The options chain is currently synthetic - Strategy outputs are paper-analysis results, not execution instructions - Symbol validation is minimal and currently delegated to downstream quote behavior