Strata Data API
The company, industry, macro and market intelligence behind the Strata mobile app, over a simple REST API. One key works here and with the Strata MCP server.
- Base URL
https://api.catalystfinance.ai/v1- Format
- JSON over HTTPS
- Spec
- OpenAPI 3.1
Quickstart
- Request access and create a key. Sign up at api.catalystfinance.ai and request API access. Once it is granted, create a key. The key is shown once, so store it somewhere safe.
- Make your first request.
curl "https://api.catalystfinance.ai/v1/tickers/AAPL?include=description" \
-H "Authorization: Bearer YOUR_API_KEY"Every endpoint, parameter and response field is described in the interactive reference, where you can also try requests with your key.
Authentication
Send your key as a bearer token on every request:
Authorization: Bearer YOUR_API_KEY- Keys start with
cat_. Each account has one active key, which you can replace or revoke from your account at any time. - Never put a key in a URL or query string, and never ship it inside a browser or mobile app.
- The same key works with the MCP server, and both share one usage allowance.
Endpoints
All paths are relative to https://api.catalystfinance.ai/v1. Each endpoint shows its main parameters; the interactive reference lists every option. Only report generation and watchlist changes write anything.
Companies
GET/tickers
Find a ticker by company name or symbol.
| Parameter | In | Required | Description |
|---|---|---|---|
q | query | Yes | Company name or the start of a symbol. |
limit | query | No | How many matches to return, from 1 to 100. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "q": "nvidia", "limit": 5,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/tickers/{ticker}
Everything Strata holds on one company: digest, profile, fundamentals, valuation, projection, technicals, risk, analysts, earnings, insiders, ownership, congressional trades, company and industry state, and its insight feed.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | path | Yes | Market symbol, such as AAPL. |
include | query | No | Sections to return, separated by commas, such as digest, fundamentals or feed. Omit it, or pass all, for every section. |
q | query | No | Search the company's insight feed by meaning. Needs feed in include (all counts). |
sources | query | No | Comma-separated insight sources. Omit for all of them. |
from | query | No | Earliest insight time, as a date or timestamp. |
to | query | No | Latest insight time, as a date or timestamp. |
order | query | No | asc or desc by publication time. Defaults to newest first. Not with q. |
view | query | No | source adds source_data, insights adds the insight card, both (the default) adds both. |
limit | query | No | Insights on this page, from 1 to 100. Defaults to 50. |
cursor | query | No | feed.page.next_cursor from the previous page. Keep the same filters. Not with q. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/AAPL"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "include": "all", "q": "iPhone demand", "sources": "news,sec_filings", "from": "2026-09-01", "to": "2026-10-20", "view": "both", "limit": 20,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/tickers/{ticker}/articles
Full research articles for one company, newest first, or ranked by meaning when you pass q.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | path | Yes | Market symbol. |
q | query | No | Rank articles by meaning. Omit for newest first. |
from | query | No | Earliest publication time. |
to | query | No | Latest publication time. |
limit | query | No | Articles to return, from 1 to 100. Defaults to 10. |
offset | query | No | Articles to skip. Not with q. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/NVDA/articles"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "q": "data center demand", "from": "2026-01-01", "to": "2026-10-20", "limit": 5,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/tickers/{ticker}/financials
Historical figures as reported in SEC filings.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | path | Yes | Market symbol. |
concept | query | No | One exact XBRL concept, such as us-gaap:GrossProfit. Omit to see every stored concept. |
family | query | No | One stored family, such as revenue. Combined with concept. |
from | query | No | Earliest period end, YYYY-MM-DD. |
to | query | No | Latest period end, YYYY-MM-DD. |
limit | query | No | Facts on this page, up to 500. Defaults to 100. |
offset | query | No | Facts to skip. Keep the same filters. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/AAPL/financials"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "concept": "us-gaap:RevenueFromContractWithCustomerExcludingAssessedTax", "family": "revenue", "from": "2024-01-01", "to": "2026-09-30", "limit": 8, "offset": 0,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/tickers/{ticker}/options
Settled options open interest and positioning.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | path | Yes | Market symbol. |
expiry | query | No | One expiry, YYYY-MM-DD. Omit for every stored expiry. |
type | query | No | call or put. Omit for both. |
limit | query | No | Contracts on this page. Defaults to 50. |
offset | query | No | Contracts to skip. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/AAPL/options"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "expiry": "2026-12-18", "type": "call", "limit": 20, "offset": 0,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/tickers/{ticker}/option-market
Option quotes and greeks, open interest by expiry, and contract price bars.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | path | Yes | Market symbol. |
expiry | query | No | One expiry, YYYY-MM-DD. |
type | query | No | call or put. Filters the quote list. |
contract | query | No | One OCC option symbol. Returns that quote and its bars. |
bar | query | No | Bar size for that contract. Defaults to daily. |
limit | query | No | Quotes, or bars when contract is set, up to 20. Defaults to 10. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/AAPL/option-market"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "expiry": "2026-12-18", "type": "call", "contract": "AAPL261218C00230000", "bar": "daily", "limit": 10,}
response = requests.get(url, headers=headers, params=params)print(response.json())POST/tickers/{ticker}/technical-analysis
Generate or reuse a full technical analysis report. Off by default; ask us to turn it on for your key.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | path | Yes | Market symbol, 1 to 5 letters. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/AAPL/technical-analysis"headers = {"Authorization": "Bearer YOUR_API_KEY"}payload = {}
response = requests.post(url, headers=headers, json=payload)print(response.json())GET/tickers/fundamentals
Compare financial ratios across up to 10 companies.
| Parameter | In | Required | Description |
|---|---|---|---|
tickers | query | Yes | One to ten symbols, separated by commas. |
metrics | query | No | Comma-separated metric names, such as pe_ratio_ttm. Omit for all 15. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/fundamentals"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "tickers": "AAPL,MSFT,NVDA", "metrics": "pe_ratio_ttm,gross_margin_ttm_pct",}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/tickers/performance
Compare split-adjusted price returns across up to 10 companies.
| Parameter | In | Required | Description |
|---|---|---|---|
tickers | query | Yes | One to ten symbols, separated by commas. |
period | query | No | ytd, 1m, 3m, 6m or 1y. Defaults to ytd. |
import requests
url = "https://api.catalystfinance.ai/v1/tickers/performance"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "tickers": "AAPL,MSFT", "period": "1y",}
response = requests.get(url, headers=headers, params=params)print(response.json())Markets and the economy
GET/market/feed
Insights across the whole market, newest first, or searched by meaning.
| Parameter | In | Required | Description |
|---|---|---|---|
q | query | No | Search by meaning. Omit for the newest insights. |
tickers | query | No | Up to ten symbols. Only used together with q. |
sources | query | No | Comma-separated sources. Omit for all of them. |
from | query | No | Earliest insight time. |
to | query | No | Latest insight time. |
order | query | No | asc or desc by publication time. Defaults to newest first. Not with q. |
limit | query | No | Insights on this page, from 1 to 100. Defaults to 50. |
cursor | query | No | feed.page.next_cursor from the previous page. Keep the same filters. Not with q. |
view | query | No | source, insights or both (the default), as on /tickers/{ticker}. |
import requests
url = "https://api.catalystfinance.ai/v1/market/feed"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "q": "semiconductor export rules", "tickers": "NVDA", "sources": "news,sec_filings", "from": "2026-09-01", "to": "2026-10-20", "limit": 10, "view": "both",}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/context
Country and commodity narratives, with market sentiment.
| Parameter | In | Required | Description |
|---|---|---|---|
ids | query | No | Comma-separated slugs, such as united_states or gold. |
category | query | No | country or commodity. The other list comes back empty. |
import requests
url = "https://api.catalystfinance.ai/v1/market/context"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "ids": "united_states,japan", "category": "country",}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/sentiment
The latest market sentiment score, or its daily history.
| Parameter | In | Required | Description |
|---|---|---|---|
from | query | No | First day, YYYY-MM-DD. Sending a date returns history instead of the latest score. |
to | query | No | Last day, YYYY-MM-DD. |
order | query | No | asc or desc. Defaults to asc in history mode. |
limit | query | No | Days on this page. Defaults to 100. |
offset | query | No | Days to skip. Continue with page.next_offset. |
import requests
url = "https://api.catalystfinance.ai/v1/market/sentiment"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "from": "2026-09-01", "to": "2026-10-20", "order": "asc", "limit": 100, "offset": 0,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/calendar
Scheduled economic releases.
| Parameter | In | Required | Description |
|---|---|---|---|
from | query | No | First day, YYYY-MM-DD. Defaults to today in UTC. |
to | query | No | Last day, YYYY-MM-DD. Defaults to six days after from. The window can span at most 31 days. |
country | query | No | One two-letter country or region code, such as US. |
min_importance | query | No | 1 low, 2 medium, 3 high. |
limit | query | No | Events on this page, up to 500. |
offset | query | No | Events to skip. |
import requests
url = "https://api.catalystfinance.ai/v1/market/calendar"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "from": "2026-10-20", "to": "2026-10-26", "country": "US", "min_importance": 2, "limit": 50, "offset": 0,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/performance
Sector or industry performance.
| Parameter | In | Required | Description |
|---|---|---|---|
level | query | No | sector or industry. Defaults to sector. |
name | query | No | One exact group name. Omit it to list every group and its name. |
import requests
url = "https://api.catalystfinance.ai/v1/market/performance"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "level": "sector", "name": "Information Technology",}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/movers
Top gainers and losers for the market, a sector, or an industry.
| Parameter | In | Required | Description |
|---|---|---|---|
scope | query | No | market, sector or industry. Defaults to market. |
name | query | No | Required for a sector or industry. Use a name from /market/performance. |
direction | query | No | gainers, losers, or both. Defaults to both. |
limit | query | No | How many names in each direction, up to 10. |
import requests
url = "https://api.catalystfinance.ai/v1/market/movers"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "scope": "sector", "name": "Information Technology", "direction": "gainers", "limit": 10,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/price-targets
Screen analyst price-target consensus by upside, sector, size and coverage.
| Parameter | In | Required | Description |
|---|---|---|---|
tickers | query | No | Up to ten symbols. Omit to screen the market. |
min_upside_pct | query | No | Smallest upside, as a signed percent. |
max_upside_pct | query | No | Largest upside. Must be at least the minimum. |
sector | query | No | One exact sector name. |
min_market_cap | query | No | Smallest stored market cap. |
min_analysts | query | No | Fewest analysts covering the name. |
limit | query | No | Rows on this page. Defaults to 25. |
offset | query | No | Rows to skip. |
import requests
url = "https://api.catalystfinance.ai/v1/market/price-targets"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "tickers": "AAPL,MSFT,NVDA", "min_upside_pct": 15, "max_upside_pct": 100, "sector": "Information Technology", "min_market_cap": 10000000000, "min_analysts": 5, "limit": 25, "offset": 0,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/insiders
Companies ranked by insider open-market buying or selling, with the prior year's pace and the other side of the same window. A company whose insiders went the other way on balance ranks after every company that did not.
| Parameter | In | Required | Description |
|---|---|---|---|
direction | query | No | buying or selling. Defaults to buying. |
days | query | No | Window ending today, from 1 to 365. Defaults to 30. |
min_insiders | query | No | Fewest distinct insiders, from 1 to 50. Use 3 for cluster buying. |
sort | query | No | value, insiders or trades. Defaults to value. |
limit | query | No | Companies to return, from 1 to 25. Defaults to 10. |
import requests
url = "https://api.catalystfinance.ai/v1/market/insiders"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "direction": "buying", "days": 30, "limit": 10,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/guidance
Guidance raises or cuts in company releases, sized by how far the guided midpoint moved against the range it replaced.
| Parameter | In | Required | Description |
|---|---|---|---|
direction | query | No | raised or lowered. Defaults to raised. |
days | query | No | Releases in the last 1 to 365 days. Defaults to 30. |
kinds | query | No | Comma-separated: revenue, eps, ebitda, net_income, capex, other. Defaults to the first four. |
limit | query | No | Companies to return, from 1 to 25. Defaults to 10. |
import requests
url = "https://api.catalystfinance.ai/v1/market/guidance"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "direction": "raised", "days": 30, "kinds": "revenue,eps", "limit": 10,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/new-highs
Stocks that closed at or near a 52-week high on heavy volume in the last few sessions. Covers the S&P 500.
| Parameter | In | Required | Description |
|---|---|---|---|
sessions | query | No | Trading sessions to look back, from 1 to 20. Defaults to 5. |
within_pct_of_high | query | No | Furthest below the 52-week high, in percent. Defaults to 1. |
min_relative_volume | query | No | Smallest session volume as a multiple of the 20-day average. Defaults to 1.5. |
limit | query | No | Stocks to return, from 1 to 30. Defaults to 15. |
import requests
url = "https://api.catalystfinance.ai/v1/market/new-highs"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "sessions": 5, "within_pct_of_high": 1, "min_relative_volume": 1.5, "limit": 15,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/market/events
Companies with a kind of event: recent ones, such as contract wins or spin-offs, or dated milestones ahead, such as FDA decisions. Found by meaning from q, then kept by Strata's event labels.
| Parameter | In | Required | Description |
|---|---|---|---|
q | query | Yes | The kind of event in plain words. |
when | query | No | recent or upcoming. Defaults to recent. |
event_types | query | No | Comma-separated event labels, such as government_contract or spin_off. |
calendar_types | query | No | With upcoming only. Comma-separated milestone kinds, such as regulatory_decision or data_readout. |
days | query | No | Window length. Defaults to 30 for recent and 90 for upcoming. |
min_market_cap | query | No | Smallest stored market cap. |
max_market_cap | query | No | Largest stored market cap. |
sector | query | No | One exact sector name. |
limit | query | No | Companies to return, from 1 to 30. Defaults to 15. |
import requests
url = "https://api.catalystfinance.ai/v1/market/events"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "q": "FDA decision date for a drug approval", "when": "upcoming", "calendar_types": "regulatory_decision", "sector": "Health Care", "limit": 15,}
response = requests.get(url, headers=headers, params=params)print(response.json())Industries, funds and signals
GET/industries
The industry catalog, with the IDs used below.
No parameters.
import requests
url = "https://api.catalystfinance.ai/v1/industries"headers = {"Authorization": "Bearer YOUR_API_KEY"}
response = requests.get(url, headers=headers)print(response.json())GET/industries/{industry_id}
The current narrative for one industry.
| Parameter | In | Required | Description |
|---|---|---|---|
industry_id | path | Yes | An id from GET /industries. Keep its case and characters. |
import requests
url = "https://api.catalystfinance.ai/v1/industries/semiconductors_and_semiconductor_equipment"headers = {"Authorization": "Bearer YOUR_API_KEY"}
response = requests.get(url, headers=headers)print(response.json())GET/funds/{ticker}
A fund's holdings.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | path | Yes | Fund ticker, such as VOO. |
limit | query | No | Holdings on this page, up to 100. Defaults to 50. |
offset | query | No | Holdings to skip. |
import requests
url = "https://api.catalystfinance.ai/v1/funds/VOO"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "limit": 25, "offset": 0,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/signals/board
The live signals leaderboard, with themes and per-ticker risk.
| Parameter | In | Required | Description |
|---|---|---|---|
direction | query | No | long, short, or both. Defaults to both. |
symbol | query | No | One exact ticker. Omit for the whole board. |
theme | query | No | One theme slug, including its subthemes. |
limit | query | No | Live candidates to return, up to 25. Defaults to 15. |
import requests
url = "https://api.catalystfinance.ai/v1/signals/board"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "direction": "long", "symbol": "NVDA", "theme": "gpu-accelerated-compute-systems", "limit": 15,}
response = requests.get(url, headers=headers, params=params)print(response.json())One record
GET/insights/{id}
One story, with its source text.
| Parameter | In | Required | Description |
|---|---|---|---|
id | path | Yes | Story id, 24 hexadecimal characters. |
text_offset | query | No | Where to start in the stored source text. Defaults to 0. |
import requests
url = "https://api.catalystfinance.ai/v1/insights/6ad7714fa5b8e2ef5b9c1908"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "text_offset": 0,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/articles/{id}
One deep-dive article.
| Parameter | In | Required | Description |
|---|---|---|---|
id | path | Yes | Article id, 24 hexadecimal characters. |
import requests
url = "https://api.catalystfinance.ai/v1/articles/ARTICLE_ID"headers = {"Authorization": "Bearer YOUR_API_KEY"}
response = requests.get(url, headers=headers)print(response.json())GET/research-handoff
One call for the current research on a signal, company, fund, story or article. Send exactly one id.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | query | No | A company or fund symbol. |
signal_id | query | No | A Strata signal id. |
insight_id | query | No | A story id, the same form as /insights/{id}. |
article_id | query | No | A deep-dive id, the same form as /articles/{id}. |
import requests
url = "https://api.catalystfinance.ai/v1/research-handoff"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "ticker": "NVDA",}
response = requests.get(url, headers=headers, params=params)print(response.json())Your portfolio
Reads need your own API key with Allow this key to read my holdings and watchlists turned on in your portal. Watchlist changes are not yet open to API keys: today only an assistant you approve for Edit your watchlists can make them, and a key gets 403 watchlist_scope_required.
GET/me/portfolio
Your linked portfolio and accounts, with update times.
No parameters.
import requests
url = "https://api.catalystfinance.ai/v1/me/portfolio"headers = {"Authorization": "Bearer YOUR_API_KEY"}
response = requests.get(url, headers=headers)print(response.json())GET/me/holdings
Your holdings, a page at a time.
| Parameter | In | Required | Description |
|---|---|---|---|
ticker | query | No | One exact stored symbol, such as AAPL. |
limit | query | No | Holdings on this page, up to 100. |
cursor | query | No | The next_cursor from the previous page. Keep the same ticker and limit. |
import requests
url = "https://api.catalystfinance.ai/v1/me/holdings"headers = {"Authorization": "Bearer YOUR_API_KEY"}params = { "ticker": "AAPL", "limit": 50,}
response = requests.get(url, headers=headers, params=params)print(response.json())GET/me/watchlists
Your watchlists, in order, each with its stocks.
No parameters.
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists"headers = {"Authorization": "Bearer YOUR_API_KEY"}
response = requests.get(url, headers=headers)print(response.json())POST/me/watchlists
Create a watchlist, optionally with a starting list of stocks.
| Parameter | In | Required | Description |
|---|---|---|---|
name | body | Yes | The list name, up to 100 characters. |
tickers | body | No | Optional starting symbols, up to 50. |
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists"headers = {"Authorization": "Bearer YOUR_API_KEY"}payload = { "name": "Semis", "tickers": [ "NVDA", "AVGO" ]}
response = requests.post(url, headers=headers, json=payload)print(response.json())PATCH/me/watchlists/{id}
Rename a watchlist.
| Parameter | In | Required | Description |
|---|---|---|---|
id | path | Yes | A watchlist id, or default for your main list. |
name | body | Yes | The new name. |
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists/default"headers = {"Authorization": "Bearer YOUR_API_KEY"}payload = { "name": "Core holdings"}
response = requests.patch(url, headers=headers, json=payload)print(response.json())PUT/me/watchlists/order
Set the order of every watchlist. Include each id once.
| Parameter | In | Required | Description |
|---|---|---|---|
watchlist_ids | body | Yes | Every watchlist id, in the new order, up to 20. |
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists/order"headers = {"Authorization": "Bearer YOUR_API_KEY"}payload = { "watchlist_ids": [ "LIST_ID_1", "LIST_ID_2" ]}
response = requests.put(url, headers=headers, json=payload)print(response.json())POST/me/watchlists/{id}/tickers
Add stocks to a watchlist. Symbols already on it are reported, not duplicated.
| Parameter | In | Required | Description |
|---|---|---|---|
id | path | Yes | A watchlist id, or default. |
tickers | body | Yes | Symbols to add, up to 50. |
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists/default/tickers"headers = {"Authorization": "Bearer YOUR_API_KEY"}payload = { "tickers": [ "AAPL", "MSFT" ]}
response = requests.post(url, headers=headers, json=payload)print(response.json())POST/me/watchlists/{id}/tickers/remove
Remove stocks from a watchlist.
| Parameter | In | Required | Description |
|---|---|---|---|
id | path | Yes | A watchlist id, or default. |
tickers | body | Yes | Symbols to remove, up to 50. |
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists/default/tickers/remove"headers = {"Authorization": "Bearer YOUR_API_KEY"}payload = { "tickers": [ "MSFT" ]}
response = requests.post(url, headers=headers, json=payload)print(response.json())PUT/me/watchlists/{id}/tickers
Set the order of the stocks in a watchlist.
| Parameter | In | Required | Description |
|---|---|---|---|
id | path | Yes | A watchlist id, or default. |
tickers | body | Yes | Exactly the stocks already on the list, in the new order, up to 200. |
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists/default/tickers"headers = {"Authorization": "Bearer YOUR_API_KEY"}payload = { "tickers": [ "NVDA", "AAPL", "MSFT" ]}
response = requests.put(url, headers=headers, json=payload)print(response.json())DELETE/me/watchlists/{id}
Delete a watchlist. Your main list cannot be deleted.
| Parameter | In | Required | Description |
|---|---|---|---|
id | path | Yes | A watchlist id. |
import requests
url = "https://api.catalystfinance.ai/v1/me/watchlists/LIST_ID"headers = {"Authorization": "Bearer YOUR_API_KEY"}
response = requests.delete(url, headers=headers)print(response.json())Responses
- Research responses carry a
metaobject and anX-Request-Idheader (the/me/endpoints do not send one yet). Quote the request ID when you contact us about a call. - Data is Strata's stored research, each item with its own timestamp. Missing coverage is returned as
nullor an empty list, never invented. - On
/tickers/{ticker},meta.coveragemarks each sectioncovered,covered_empty(on record, nothing for this section) ornot_covered, andmeta.coverage_summary.researchedsays whether Strata actively researches the company. Check them before reading an empty section as “nothing to report”. - Unknown or repeated query parameters are rejected rather than silently ignored.
Errors
Errors share one shape. The /me/ endpoints leave out request_id.
{
"error": { "code": "invalid_api_token", "message": "..." },
"request_id": "..."
}| Status | Codes | Meaning |
|---|---|---|
| 400 | invalid_*, unknown_query_parameter | A parameter is missing, malformed or not recognised. |
| 401 | missing_api_token, invalid_api_token | No key was sent, or the key is not valid. |
| 403 | generation_not_allowed, portfolio_scope_required, watchlist_scope_required | The key lacks the permission this call needs: report generation, holdings access or watchlist editing. |
| 404 | not_found, industry_not_found, fund_not_found, watchlist_not_found | No such story, article, industry, fund, watchlist or route. An unknown ticker is not a 404; its sections come back empty. |
| 409 | ambiguous_fund, watchlist_name_taken, watchlist_order_mismatch | The fund ticker matches several funds, or a watchlist change conflicts with what is stored. |
| 429 | rate_limited | Over your allowance. Wait for the Retry-After seconds, then try again. |
| 500 | internal_error | Something went wrong on our side. |
| 503 | api_busy, api_unavailable, temporarily_unavailable | Temporarily unavailable. Retry after a short wait. |
The full list of codes is in the interactive reference.
Limits
- The default allowance is 60 requests a minute and 10,000 a day (UTC), shared between the API and MCP. Need more? Talk to us.
- Report generation is off by default. Once turned on, it has its own limit of 5 a minute.
- Watchlist changes are limited to 60 an hour per account.
- Over the limit you get
429 rate_limitedwith aRetry-Afterheader. Wait that many seconds before retrying. 503 api_busyalso sendsRetry-After. Back off and retry.
Pagination
- Insight feeds use cursors: pass
feed.page.next_cursorascursorwhilefeed.page.has_moreis true. A cursor belongs to its filters, so changing a filter means starting again. A search withqreturns one ranked page and cannot be continued. /me/holdingsworks the same way withpagination.next_cursor.- Lists that take
offsetreturnpage.has_moreandpage.next_offset(underhistoryon/market/sentimentandholdingson/funds/{ticker}). - New response fields can appear at any time, so ignore fields you do not recognise.
The same research inside an assistant. MCP server