Files
market_screener/api_collections/market-screener.postman_collection.json
T

1151 lines
39 KiB
JSON

{
"info": {
"name": "Market Screener API",
"description": "Full test suite for the market-screener Fastify server.\n\nBase URL is stored in the `baseUrl` collection variable (default: http://localhost:3000).\n\nWorkflow order for a clean session:\n1. Health Check\n2. Screen Tickers (creates results to inspect)\n3. Get Market Context\n4. Get Catalysts\n5. Add Holdings \u2192 Get Portfolio\n6. Create Market Call \u2192 Get Call \u2192 Calendar\n7. Analyze\n8. Cleanup (delete holding, delete call)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"variable": [
{
"key": "baseUrl",
"value": "http://localhost:3000",
"type": "string"
},
{
"key": "callId",
"value": "",
"type": "string",
"description": "Set automatically by the Create Market Call test script"
},
{
"key": "jwt",
"value": "",
"type": "string"
}
],
"item": [
{
"name": "Health",
"item": [
{
"name": "Health Check",
"request": {
"method": "GET",
"url": "{{baseUrl}}/health",
"description": "Confirms the server is running. Expects { status: 'ok' }."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"pm.test('Body has status ok', () => {",
" const json = pm.response.json();",
" pm.expect(json.status).to.eql('ok');",
"});"
]
}
}
]
}
]
},
{
"name": "Screener",
"item": [
{
"name": "Screen \u2014 Mixed (STOCK + ETF + BOND)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/screen",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"tickers\": [\"AAPL\", \"MSFT\", \"GOOGL\", \"VOO\", \"AGG\"]\n}"
},
"description": "Screens a mixed set of stocks, an ETF (VOO), and a bond ETF (AGG).\n\nExpect each result to have:\n- asset.ticker, asset.type, asset.currentPrice\n- asset.displayMetrics (Cap Tier, Style, Analyst, DCF Safety, 52W fields)\n- fundamental + inflated score labels\n- signal (Strong Buy / Momentum / Speculation / Neutral / Avoid)\n- marketContext (riskFreeRate, rateRegime, benchmarks)"
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('Response shape is valid', () => {",
" const json = pm.response.json();",
" pm.expect(json).to.have.all.keys('STOCK', 'ETF', 'BOND', 'ERROR', 'marketContext');",
"});",
"",
"pm.test('marketContext has required fields', () => {",
" const ctx = pm.response.json().marketContext;",
" pm.expect(ctx).to.have.property('riskFreeRate');",
" pm.expect(ctx).to.have.property('rateRegime');",
" pm.expect(ctx.benchmarks).to.have.all.keys('marketPE', 'techPE', 'reitYield', 'igSpread');",
"});",
"",
"pm.test('Each stock has expert fields in displayMetrics', () => {",
" const stocks = pm.response.json().STOCK;",
" if (stocks.length === 0) return;",
" const dm = stocks[0].asset.displayMetrics;",
" pm.expect(dm).to.have.property('Cap Tier');",
" pm.expect(dm).to.have.property('Style');",
"});",
"",
"pm.test('Each stock has a signal', () => {",
" pm.response.json().STOCK.forEach(r => {",
" pm.expect(r.signal).to.be.oneOf([",
" '\u2705 Strong Buy', '\u26a1 Momentum', '\u26a0\ufe0f Speculation', '\ud83d\udd04 Neutral', '\u274c Avoid'",
" ]);",
" });",
"});"
]
}
}
]
},
{
"name": "Screen \u2014 Tech Stocks (tests TECHNOLOGY sector override)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/screen",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"tickers\": [\"NVDA\", \"META\", \"AMZN\", \"TSLA\"]\n}"
},
"description": "High-growth tech tickers to validate DCF margin-of-safety scoring, analyst consensus, and 52W movement fields. Expect 'High Growth' in Style field for most."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('52W fields present when data available', () => {",
" pm.response.json().STOCK.forEach(r => {",
" const dm = r.asset.displayMetrics;",
" // at least one 52W field should be populated",
" const has52W = dm['52W Chg'] || dm['From High'] || dm['52W Pos'];",
" pm.expect(has52W).to.be.ok;",
" });",
"});",
"",
"pm.test('DCF or analyst field present for stocks with FCF', () => {",
" // Not all stocks will have positive FCF, but at least one should have DCF",
" const stocks = pm.response.json().STOCK;",
" const hasDcf = stocks.some(r => r.asset.displayMetrics['DCF Safety'] != null);",
" const hasAnalyst = stocks.some(r => r.asset.displayMetrics['Analyst'] != null);",
" pm.expect(hasDcf || hasAnalyst).to.be.true;",
"});"
]
}
}
]
},
{
"name": "Screen \u2014 REIT (tests P/FFO scoring path)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/screen",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"tickers\": [\"O\", \"VICI\", \"PLD\"]\n}"
},
"description": "REITs should show sector REIT, P/FFO in displayMetrics (not P/E), and be scored on yield rather than the standard Graham gates."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('REITs land in STOCK bucket with REIT sector', () => {",
" pm.response.json().STOCK.forEach(r => {",
" pm.expect(r.asset.displayMetrics['Sector']).to.eql('REIT');",
" });",
"});"
]
}
}
]
},
{
"name": "Screen \u2014 Validation: empty tickers (expect 400)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/screen",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"tickers\": []\n}"
},
"description": "Schema validation: minItems: 1. Expect 400 Bad Request."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 400 for empty array', () => pm.response.to.have.status(400));"
]
}
}
]
},
{
"name": "Screen \u2014 Validation: over 50 tickers (expect 400)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/screen",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"tickers\": [\"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\",\"P\",\"Q\",\"R\",\"S\",\"T\",\"U\",\"V\",\"W\",\"X\",\"Y\",\"Z\",\"AA\",\"BB\",\"CC\",\"DD\",\"EE\",\"FF\",\"GG\",\"HH\",\"II\",\"JJ\",\"KK\",\"LL\",\"MM\",\"NN\",\"OO\",\"PP\",\"QQ\",\"RR\",\"SS\",\"TT\",\"UU\",\"VV\",\"WW\",\"XX\",\"YY\"]\n}"
},
"description": "Schema validation: maxItems: 50. 51 tickers should return 400."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 400 for 51 tickers', () => pm.response.to.have.status(400));"
]
}
}
]
},
{
"name": "Get Catalysts",
"request": {
"method": "GET",
"url": "{{baseUrl}}/api/screen/catalysts",
"description": "Fetches today's Yahoo Finance news, extracts ticker symbols mentioned, and returns { tickers, stories }. May take 3-5s as it queries multiple news endpoints."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('Response has tickers and stories arrays', () => {",
" const json = pm.response.json();",
" pm.expect(json.tickers).to.be.an('array');",
" pm.expect(json.stories).to.be.an('array');",
"});"
]
}
}
]
}
]
},
{
"name": "Market Context",
"item": [
{
"name": "Get Market Context",
"request": {
"method": "GET",
"url": "{{baseUrl}}/api/finance/market-context",
"description": "Returns live benchmark data: S&P500 price, 10Y rate, VIX, SPY P/E, XLK P/E, XLRE yield, LQD spread. Served from 1-hour in-memory cache."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('All benchmark fields present', () => {",
" const json = pm.response.json();",
" pm.expect(json).to.have.property('sp500Price');",
" pm.expect(json).to.have.property('riskFreeRate');",
" pm.expect(json).to.have.property('vixLevel');",
" pm.expect(json).to.have.property('rateRegime');",
" pm.expect(json.rateRegime).to.be.oneOf(['LOW', 'NORMAL', 'HIGH']);",
" pm.expect(json.benchmarks).to.have.all.keys('marketPE', 'techPE', 'reitYield', 'igSpread');",
"});"
]
}
}
]
}
]
},
{
"name": "Portfolio",
"item": [
{
"name": "Add Holding \u2014 AAPL",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/finance/holdings",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ticker\": \"AAPL\",\n \"shares\": 10,\n \"costBasis\": 150.00,\n \"type\": \"stock\",\n \"source\": \"Robinhood\"\n}"
},
"description": "Adds or updates an AAPL holding in portfolio.json. Returns the saved holding with status 201."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 201', () => pm.response.to.have.status(201));",
"",
"pm.test('Saved holding matches input', () => {",
" const json = pm.response.json();",
" pm.expect(json.ticker).to.eql('AAPL');",
" pm.expect(json.shares).to.eql(10);",
" pm.expect(json.costBasis).to.eql(150);",
"});"
]
}
}
]
},
{
"name": "Add Holding \u2014 VOO (ETF)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/finance/holdings",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ticker\": \"VOO\",\n \"shares\": 5,\n \"costBasis\": 420.00,\n \"type\": \"etf\",\n \"source\": \"Vanguard\"\n}"
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 201', () => pm.response.to.have.status(201));"
]
}
}
]
},
{
"name": "Add Holding \u2014 BTC-USD (Crypto, no scoring)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/finance/holdings",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ticker\": \"BTC-USD\",\n \"shares\": 0.1,\n \"costBasis\": 50000,\n \"type\": \"crypto\",\n \"source\": \"Coinbase\"\n}"
},
"description": "Crypto is priced via Yahoo but not fundamentally scored. Advice column shows '\u2014' for signal."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 201', () => pm.response.to.have.status(201));"
]
}
}
]
},
{
"name": "Add Holding \u2014 Validation: missing shares (expect 400)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/finance/holdings",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"ticker\": \"MSFT\"\n}"
},
"description": "Schema validation: shares is required. Expect 400."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 400 when shares missing', () => pm.response.to.have.status(400));"
]
}
}
]
},
{
"name": "Get Portfolio",
"request": {
"method": "GET",
"url": "{{baseUrl}}/api/finance/portfolio",
"description": "Screens all non-crypto holdings via Yahoo Finance, then cross-references with signals to produce buy/hold/sell advice.\n\nEach row has: ticker, signal, advice, reason, currentPrice, marketValue, gainLossPct.\nAlso returns marketContext.\n\nNote: first call after server start may be slow (benchmark cache cold)."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('Advice array present', () => {",
" const json = pm.response.json();",
" pm.expect(json.advice).to.be.an('array');",
" pm.expect(json.advice.length).to.be.greaterThan(0);",
"});",
"",
"pm.test('Each advice row has required fields', () => {",
" pm.response.json().advice.forEach(row => {",
" pm.expect(row).to.have.property('ticker');",
" pm.expect(row).to.have.property('advice');",
" pm.expect(row).to.have.property('reason');",
" });",
"});"
]
}
}
]
},
{
"name": "Remove Holding \u2014 AAPL",
"request": {
"method": "DELETE",
"url": "{{baseUrl}}/api/finance/holdings/AAPL",
"description": "Removes the AAPL holding from portfolio.json. Expect { ok: true }."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"pm.test('ok true', () => pm.expect(pm.response.json().ok).to.be.true);"
]
}
}
]
},
{
"name": "Remove Holding \u2014 Non-existent (expect 404)",
"request": {
"method": "DELETE",
"url": "{{baseUrl}}/api/finance/holdings/ZZZZZZ",
"description": "Ticker does not exist in portfolio. Expect 404."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 404', () => pm.response.to.have.status(404));"
]
}
}
]
}
]
},
{
"name": "Market Calls",
"item": [
{
"name": "List Calls (empty or existing)",
"request": {
"method": "GET",
"url": "{{baseUrl}}/api/calls",
"description": "Returns all market calls sorted newest first. Returns { calls: [] } if none exist yet."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"pm.test('calls is array', () => pm.expect(pm.response.json().calls).to.be.an('array'));"
]
}
}
]
},
{
"name": "Create Market Call",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/calls",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"title\": \"AI Infrastructure Supercycle\",\n \"quarter\": \"Q3 2025\",\n \"thesis\": \"Hyperscaler capex remains elevated through 2026 driven by LLM training demand. NVDA, MSFT and AMD are the primary beneficiaries. Entry here as NVDA pulled back 15% from high.\",\n \"tickers\": [\"NVDA\", \"MSFT\", \"AMD\"]\n}"
},
"description": "Creates a market thesis call. Snapshots current prices + screener signals at creation time for future comparison.\n\nThe test script saves the returned ID to the {{callId}} collection variable for use in subsequent requests."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 201', () => pm.response.to.have.status(201));",
"",
"pm.test('Call has id, snapshot, and createdAt', () => {",
" const json = pm.response.json();",
" pm.expect(json).to.have.property('id');",
" pm.expect(json).to.have.property('snapshot');",
" pm.expect(json).to.have.property('createdAt');",
" // Save for downstream tests",
" pm.collectionVariables.set('callId', json.id);",
"});"
]
}
}
]
},
{
"name": "Get Call by ID (with current re-screen)",
"request": {
"method": "GET",
"url": "{{baseUrl}}/api/calls/{{callId}}",
"description": "Fetches the call and re-screens all tickers to show how signal/price has changed since creation.\n\nReturns: original call fields + `current` map of ticker \u2192 { price, signal, inflatedVerdict, fundamentalVerdict, pe, roe, fcf }.\n\nDepends on {{callId}} being set by the Create Market Call request."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('Response has snapshot and current', () => {",
" const json = pm.response.json();",
" pm.expect(json).to.have.property('snapshot');",
" pm.expect(json).to.have.property('current');",
"});"
]
}
}
]
},
{
"name": "Get Call \u2014 Non-existent ID (expect 404)",
"request": {
"method": "GET",
"url": "{{baseUrl}}/api/calls/00000000-0000-0000-0000-000000000000",
"description": "A UUID that doesn't exist. Expect 404."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 404', () => pm.response.to.have.status(404));"
]
}
}
]
},
{
"name": "Get Earnings Calendar (call tickers)",
"request": {
"method": "GET",
"url": "{{baseUrl}}/api/calls/calendar",
"description": "Returns upcoming earnings dates and dividend events for all tickers across all saved calls.\n\nOptional query param ?tickers=AAPL,MSFT to restrict to specific tickers."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"",
"pm.test('events is array', () => {",
" pm.expect(pm.response.json().events).to.be.an('array');",
"});",
"",
"pm.test('Events have expected shape', () => {",
" pm.response.json().events.forEach(e => {",
" pm.expect(e).to.have.property('ticker');",
" pm.expect(e).to.have.property('type');",
" pm.expect(e.type).to.be.oneOf(['earnings', 'dividend', 'exdividend']);",
" pm.expect(e).to.have.property('date');",
" pm.expect(e).to.have.property('isPast');",
" });",
"});"
]
}
}
]
},
{
"name": "Get Earnings Calendar \u2014 Specific Tickers",
"request": {
"method": "GET",
"url": {
"raw": "{{baseUrl}}/api/calls/calendar?tickers=AAPL,MSFT",
"query": [
{
"key": "tickers",
"value": "AAPL,MSFT"
}
]
},
"description": "Calendar for specific tickers regardless of saved calls."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"pm.test('Only AAPL and MSFT events', () => {",
" pm.response.json().events.forEach(e => {",
" pm.expect(e.ticker).to.be.oneOf(['AAPL', 'MSFT']);",
" });",
"});"
]
}
}
]
},
{
"name": "Create Call \u2014 Validation: short thesis (expect 400)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/calls",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"title\": \"Test\",\n \"quarter\": \"Q1\",\n \"thesis\": \"short\",\n \"tickers\": [\"AAPL\"]\n}"
},
"description": "Schema: thesis minLength: 10. Expect 400."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 400 for short thesis', () => pm.response.to.have.status(400));"
]
}
}
]
},
{
"name": "Delete Call",
"request": {
"method": "DELETE",
"url": "{{baseUrl}}/api/calls/{{callId}}",
"description": "Deletes the call created earlier. Returns { ok: true }. Requires {{callId}} to be set."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200', () => pm.response.to.have.status(200));",
"pm.test('ok true', () => pm.expect(pm.response.json().ok).to.be.true);"
]
}
}
]
},
{
"name": "Delete Call \u2014 Already Deleted (expect 404)",
"request": {
"method": "DELETE",
"url": "{{baseUrl}}/api/calls/{{callId}}",
"description": "Second delete of the same ID. Expect 404."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 404 on double delete', () => pm.response.to.have.status(404));"
]
}
}
]
}
]
},
{
"name": "LLM Analysis",
"item": [
{
"name": "Analyze Tickers",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/analyze",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"tickers\": [\"NVDA\", \"AMD\", \"INTC\"]\n}"
},
"description": "Fetches Yahoo Finance news for the given tickers, then sends headlines to Claude (Haiku) for analysis.\n\nReturns: { analysis: { summary, sentiment, affectedIndustries, relatedTickers } }\n\nReturns 400 if ANTHROPIC_API_KEY is not set in .env.\nReturns { analysis: null, reason: 'no_stories' } if no news found."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 200 or 400', () => {",
" pm.expect(pm.response.code).to.be.oneOf([200, 400]);",
"});",
"",
"if (pm.response.code === 200) {",
" pm.test('Analysis shape valid (if present)', () => {",
" const json = pm.response.json();",
" if (json.analysis) {",
" pm.expect(json.analysis).to.have.property('summary');",
" pm.expect(json.analysis).to.have.property('sentiment');",
" pm.expect(json.analysis.sentiment).to.be.oneOf(['BULLISH', 'NEUTRAL', 'BEARISH']);",
" pm.expect(json.analysis.affectedIndustries).to.be.an('array');",
" pm.expect(json.analysis.relatedTickers).to.be.an('array');",
" }",
" });",
"} else {",
" pm.test('400 means API key not set', () => {",
" pm.expect(pm.response.json().error).to.include('ANTHROPIC_API_KEY');",
" });",
"}"
]
}
}
]
},
{
"name": "Analyze \u2014 Validation: empty tickers (expect 400)",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/analyze",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"tickers\": []\n}"
},
"description": "Schema validation: minItems: 1. Expect 400."
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Status 400', () => pm.response.to.have.status(400));"
]
}
}
]
}
]
},
{
"name": "Screener \u2014 Ticker Detail & Sectors (June 2026)",
"item": [
{
"name": "Signal history (snapshot ledger)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/screen/history/AAPL",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"screen",
"history",
"AAPL"
]
},
"description": "Per-day signal/tier/score history from the signal_snapshots ledger (P0.1)."
}
},
{
"name": "Company profile",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/screen/profile/AAPL",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"screen",
"profile",
"AAPL"
]
},
"description": "Name, description, sector, market cap + analyst targets (mean/high/low, upside). Cached 1h."
}
},
{
"name": "Price chart",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/screen/chart/AAPL?range=6mo",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"screen",
"chart",
"AAPL"
],
"query": [
{
"key": "range",
"value": "6mo"
}
]
},
"description": "Closes for the ticker modal chart. range: 1d|5d|1mo|3mo|6mo|ytd|1y|5y (intraday bars for 1d/5d)."
}
},
{
"name": "Sector pulse",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/screen/sectors",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"screen",
"sectors"
]
},
"description": "Today's % change per sector via SPDR ETFs, sorted best\u2192worst, with leader. Cached 15m."
}
},
{
"name": "Sector drill-down",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/screen/sector/TECHNOLOGY",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"screen",
"sector",
"TECHNOLOGY"
]
},
"description": "Top-10 ETF holdings screened + 3-day sector news. Sectors: TECHNOLOGY, FINANCIAL, ENERGY, HEALTHCARE, COMMUNICATION, CONSUMER_STAPLES, CONSUMER_DISCRETIONARY, REIT. Cached 30m."
}
}
]
},
{
"name": "News & Digest (June 2026)",
"item": [
{
"name": "News for ticker (stored + live merge)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/news/AAPL?days=7&live=1",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"news",
"AAPL"
],
"query": [
{
"key": "days",
"value": "7"
},
{
"key": "live",
"value": "1"
}
]
},
"description": "Stored pipeline stories (EDGAR + PR wires, catalyst-tagged) merged with a live Yahoo search. live=0 for stored only."
}
},
{
"name": "Recent news (all tickers)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/news/recent?limit=50",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"news",
"recent"
],
"query": [
{
"key": "limit",
"value": "50"
}
]
},
"description": ""
}
},
{
"name": "Daily digest (today)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/digest",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"digest"
]
},
"description": "Signal flips vs previous snapshots + news catalysts + M&A stories."
}
},
{
"name": "Daily digest (specific day)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/digest?date=2026-06-12",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"digest"
],
"query": [
{
"key": "date",
"value": "2026-06-12"
}
]
},
"description": ""
}
}
]
},
{
"name": "Auth & Watchlist",
"item": [
{
"name": "Register",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"url": {
"raw": "{{baseUrl}}/auth/register",
"host": [
"{{baseUrl}}"
],
"path": [
"auth",
"register"
]
},
"description": "Invite code is printed in the server terminal on boot (hidden during tests).",
"body": {
"mode": "raw",
"raw": "{\n \"email\": \"you@example.com\",\n \"password\": \"min-8-chars\",\n \"inviteCode\": \"<printed on server boot>\"\n}"
}
}
},
{
"name": "Login",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"url": {
"raw": "{{baseUrl}}/auth/login",
"host": [
"{{baseUrl}}"
],
"path": [
"auth",
"login"
]
},
"description": "Returns { token } \u2014 save as {{jwt}} collection variable.",
"body": {
"mode": "raw",
"raw": "{\n \"email\": \"you@example.com\",\n \"password\": \"min-8-chars\"\n}"
}
}
},
{
"name": "Get watchlist",
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "Bearer {{jwt}}"
}
],
"url": {
"raw": "{{baseUrl}}/api/watchlist",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"watchlist"
]
},
"description": ""
}
},
{
"name": "Pin ticker",
"request": {
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "Bearer {{jwt}}"
}
],
"url": {
"raw": "{{baseUrl}}/api/watchlist/AAPL",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"watchlist",
"AAPL"
]
},
"description": ""
}
},
{
"name": "Unpin ticker",
"request": {
"method": "DELETE",
"header": [
{
"key": "Authorization",
"value": "Bearer {{jwt}}"
}
],
"url": {
"raw": "{{baseUrl}}/api/watchlist/AAPL",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"watchlist",
"AAPL"
]
},
"description": ""
}
}
]
}
]
}