Sign up

Products

Status

News & Sentiment

Equity news and sentiment in one product: a seconds-fresh cross-publisher newswire, one-call news digests per ticker, filtered news search, detected market events, analyst rating actions, and daily sentiment scores back to 2000. Use it to spot catalysts, explain a move, and measure whether the news backdrop is turning.

What's inside

  • Live newswire. Cross-publisher headlines with publisher, tickers, an is_major flag and feed-supplied sentiment, seconds-to-minutes fresh.
  • Newswire stories and explainers. Full newswire stories by ticker or channel with history back to 2018, "Why It's Moving" explainers with a catalyst type, the movers channel, company press releases and the crypto channel.
  • Per-ticker news. A one-call digest (recent stories, sentiment, trending status, events and analyst actions), raw headlines over a short window, company-only coverage, co-mention feeds and a full filtered search.
  • Market-wide news. Aggregated cross-source feed, category and topic feeds on the news source's own categories (earnings, M&A, dividends, layoffs, lawsuits and more), headline-only alerts and an end-of-day digest.
  • Events. Detected market-moving events, structured events by type, and every article clustered under one event id.
  • Sentiment. Daily sentiment per ticker (-1.5 to +1.5), market-wide rollups, most-mentioned tickers, and a deep daily sentiment history per company from 2000.
  • Analysts. Consensus rating with price-target bands, and rating actions (upgrades, downgrades, initiations) back to 2022-04-08.
  • Social attention. A daily Twitter follower count with its weekly percent change per ticker. There is no mention count, and the upstream dataset was found returning no rows for any ticker in July 2026 (see the notes below).

Crypto news with sentiment is on the Crypto page and FX news is on Macro, Rates & FX. The r/wallstreetbets feed is part of Alt-Data.

Access

Note:

2 credits/call · Starter and up

Which endpoint to call

  • "What's the news on X?" Start with GET /api/v3/news/summary/{ticker}. It answers most single-ticker questions in one call. Reach for the drill-down routes (news/latest, news/trending) only when the summary is not enough.
  • "What's happening in the market right now?" GET /api/v3/intel/news_headlines (fastest wire) or GET /api/v3/news/aggregated.
  • "Why is X moving today?" GET /api/v3/intel/news_why_moving?tickers=X. For "what moved today", GET /api/v3/intel/news_movers.
  • "Did anything big happen today?" GET /api/v3/news/events or GET /api/v3/news/curated_events.
  • News with filters (topic, source, sentiment, keyword): GET /api/v3/news/ticker_news. For sector or industry news, GET /api/v3/news/category.
  • "Headlines on X in the last few hours": GET /api/v3/news/aggregated?ticker=X&hours=N.
  • How sentiment is trending: GET /api/v3/news/sentiment_stats for recent days, GET /api/v3/news/sentiment_history/{ticker} for years.

Endpoints

date_range on the newswire routes accepts today, yesterday, last7days, last30days, or a custom MMDDYYYY-MMDDYYYY window (sentiment_stats also takes last60days). items is the page size and page the page number where a route paginates.

One ticker

MethodPathMCP toolDescription
GET/api/v3/news/summary/{ticker}news_summaryOne-shot news for a ticker: recent_news (today), 7-day sentiment_stats, trending, 7-day events and analyst_actions, plus news_count_24h. The primary call for a single name. 90 s cache.
GET/api/v3/news/latestnews_latestDrill-down only. Raw newswire headlines for one ticker over a short look-back. Query: ticker (the one symbol to read; a request without it is rejected with 422), minutes (5–1440, default 60). Up to 60 the look-back snaps to the newswire's windows of 5, 10, 15, 30, 45 or 60 minutes; above 60 it reads the last 7 days and keeps the headlines published inside the window (up to 50). Returns {ticker, window_minutes, items[]}; an empty window carries a note saying the source answered with nothing, so it is not read as "no news exists". 60 s cache.
GET/api/v3/news/trendingnews_trendingDrill-down only. The newswire's noise-filtered top stories, for one ticker (ticker, optional) or the whole market. Returns {ticker, items[]}.
GET/api/v3/news/ticker_onlynews_ticker_onlyStories tagged with only this ticker, excluding articles that co-tag peers. Query: ticker (required), items (1–50, default 50), page (1–50, default 1). Returns {ticker, items[], n}.
GET/api/v3/news/multi_tickernews_multi_tickerStories where all the listed tickers appear in the same article (deals, rivalries, shared catalysts). Query: tickers (required, comma-separated), items (1–50, default 50), page (1–50, default 1). Returns {tickers[], items[], n}.
GET/api/v3/news/ticker_newsnews_ticker_newsFiltered search for when you have filters, not for plain "news on X". Query: tickers (required, comma-separated), items (1–50, default 50), page (1–50, default 1), date_range, topic, topic_or, topic_exclude (see News topics; topic_or and topic_exclude take a comma list), source, source_exclude, news_type (article|video), sentiment (positive|negative|neutral), sortby (rank|oldestfirst), days (1–30, used with sortby=rank), search, search_or, fallback (bool, default false). Returns {tickers[], items[], n}. There is no sector filter here: the source ignores it beside tickers, so sector is refused with 422 unsupported_filter; filter by sector on news/category.

Market-wide news

MethodPathMCP toolDescription
GET/api/v3/intel/news_headlinesintel_news_headlinesMarket-wide live newswire. Each item carries headline, publisher, created_at, tickers[], is_major, sentiment and tags[]. Query: ticker (optional filter), limit (1–100, default 50). For one company's news use news_summary. Returns {ticker, items[], count, as_of, source}. 120 s cache.
GET/api/v3/news/aggregatednews_aggregatedAggregated cross-source feed published in the last hours, newest first: market-wide, or for one ticker. Query: hours (1–168, default 24, a trailing window), limit (1–1000, default 100), ticker (optional, one symbol). One call reads at most 150 items (coverage.max_items_read), and coverage.complete is false, with a note, when the answer does not reach back to the window's start. With ticker, only headlines the source tags with that symbol are served, source is news_ticker, and the answer echoes ticker; no headline in the window is an empty news list with a note and symbol_check, and a symbol no listing knows is 404 unknown_ticker, not billed. A list in ticker is refused with a 422; for several symbols use news/ticker_news. Returns {news[], window_hours, ticker, date_range, source, coverage}; ticker is null market-wide. Not de-duplicated: a story carried by several outlets appears once per outlet.
GET/api/v3/news/categorynews_categoryThemed or sector-level news. Query: section (general for market-wide, alltickers for company-tagged stories; default general), topic (optional, one of the news topics), sector, industry, source, items (1–50, default 50), page (1–50, default 1), date_range. Returns {section, topic, sector, industry, source, date_range, items[], n}.
GET/api/v3/news/by_topicnews_by_topicHeadlines on one event type, optionally for one ticker. Query: topic (required, one of the news topics; anything else is 422 invalid_topic), ticker, items (1–50, default 50), date_range (default last7days). Returns {topic, source_topic, ticker, date_range, items[]}: topic is your word and source_topic the category sent to the source.
GET/api/v3/news/alertsnews_alertsHeadline-only alerts, lighter and faster than full items. Query: category (general for market alerts, ticker to scope by tickers; omit for the latest cross-wire headlines), tickers (comma-separated; tickers alone means category=ticker, and tickers with category=general is 422 unsupported_filter), items (1–100, default 100), page (1–50, default 1). Returns {category, tickers, items[], n}. 30 s cache.
GET/api/v3/news/sundownnews_sundownCurated end-of-day market recap. Query: date_range (optional). Returns {date_range, digest[]}.

Newswire stories

Five routes over the newswire, live, newest first. Each item carries id, title, teaser, url, tickers, channels and tags (lower case), published (UTC) and updated; body=true adds the full HTML body. date_from and date_to (UTC days, inclusive, at most 366 days apart) read past windows back to 2018. An empty list is a real empty answer (result: "empty_but_healthy"); a feed that did not answer is a 503 refusal, never an empty list. Quote each story with its time.

MethodPathMCP toolDescription
GET/api/v3/intel/news_prointel_news_proNewswire stories, cross-ticker, by ticker (comma-separated, up to 20) or by channel. Items also carry ticker, coins (crypto assets named), author and created (the same instant as published). Channel names are the feed's, lower case, such as movers, press releases, cryptocurrency, earnings, guidance, analyst ratings, price target, markets, top stories, economics and federal reserve; Why It's Moving selects the move explainers. as_of is the newest item's publication time. Use it for themed or full-text news beyond headlines. Query: tickers, channels, limit (1–100, default 25), body, date_from, date_to.
GET/api/v3/intel/news_why_movingintel_news_why_moving"Why It's Moving" explainers: short stories on why a stock or coin is making a notable move, each with catalyst_type (earnings, guidance, analyst, ma, regulatory, capital, contract, personnel, macro or other: a keyword reading of the headline, not a model). Explainers are written on US trading days, so the newest can be a day or more old over a weekend. Call it first for "why is X moving today?". Query: tickers (optional), limit (1–100, default 25), body, date_from, date_to.
GET/api/v3/intel/news_moversintel_news_moversThe movers channel: stories on the biggest gainers, losers, halts and breakouts. A story from an earlier session is not today's mover. Use it for "what moved today" questions and end-of-day recaps. Query: tickers, limit (1–100, default 25), body, date_from, date_to.
GET/api/v3/intel/news_press_releasesintel_news_press_releasesCompany press releases carried on the newswire. Coverage is sparse: about fifty releases from March 2024 to September 2026, so the newest can be weeks old (the staleness block grades it against a 14-day cadence), and an empty answer does not show that a company issued none. Query: tickers, limit (1–100, default 25), body, date_from, date_to.
GET/api/v3/intel/news_cryptointel_news_cryptoThe newswire's cryptocurrency channel, with coins on each item. tickers takes coins or coin-stock proxies (COIN, MSTR); see Crypto for how a symbol shared by a coin and a stock is read. Query: tickers, limit (1–100, default 25), body, date_from, date_to, asset_class.

News topics

topic on by_topic and category, and topic, topic_or and topic_exclude on ticker_news, take the news source's own categories. Case does not matter.

  • earnings, dividend (or dividends), layoffs, lawsuit, product, ceo, podcast, oil, futures.
  • mergers for M&A. acquisition, acquisitions, mergers_acquisitions, m&a and manda mean the same; all are sent as manda.
  • pricemovement (or price_movement), tanalysis for technical analysis (or technical_analysis), and pressrelease (or press_release).
  • The access tags paywall and paylimitwall, most useful in topic_exclude to drop paywalled articles.

Anything else returns 422 with error: "invalid_topic", and detail names the supported topics; the source is not called and the call is not billed. That includes ipo, fda, analysts, pricetarget, guidance, stock_buyback, stocksplit, partnership, spinoff, bankruptcy, insider, esg and crypto, which this page used to list. The source has no such category, so they always answered an empty list, which read as "no news"; the 422 now says there is no such category. For those subjects use search on ticker_news, and news/ratings for analyst actions.

by_topic echoes your word in topic and the category it sent in source_topic: topic=mergers answers topic: "mergers" and source_topic: "manda". category echoes your word in topic.

Events and catalysts

MethodPathMCP toolDescription
GET/api/v3/news/eventsnews_eventsDetected market-moving events across the market. Query: hours (1–168, default 24, a trailing window cut by each event's date, read the same way as news/aggregated). Returns {events[], window_hours, date_range, source, coverage}.
GET/api/v3/news/curated_eventsnews_curated_eventsStructured events (earnings, M&A, FDA decisions, guidance changes, price-target moves and more). Query: ticker, event_type (for example earnings, mergers, acquisition, pricetarget, fda, guidance), date_range (default today), items (1–50, default 50). Returns {ticker, event_type, date_range, events[]}.
GET/api/v3/news/event_by_idnews_event_by_idEvery article clustered under one event. Query: eventid (required, taken from another news result), items (1–50, default 50), page (1–20, default 1). Returns {eventid, items[], n}.

Sentiment

MethodPathMCP toolDescription
GET/api/v3/news/sentiment_statsnews_sentiment_statsDaily sentiment for one ticker: a -1.5 to +1.5 sentiment_score per day with positive, negative and neutral article counts. Query: ticker (required), date_range (default last30days). A day with no articles is absent, not zero. Returns {ticker, date_range, stats}.
GET/api/v3/news/market_sentimentnews_market_sentimentMarket-wide daily sentiment rollup of general market news. Query: date_range (default last7days). Returns {date_range, market}.
GET/api/v3/news/all_tickers_sentimentnews_all_tickers_sentimentDaily sentiment rollup across company-tagged news for the whole tracked universe. Query: date_range (default last7days), page (1–20, default 1). Returns {date_range, page, stats}. The rows are one aggregate per day (bucket counts and sentiment_score) and carry no per-ticker breakdown; for per-ticker sentiment call sentiment_stats.
GET/api/v3/news/top_mentionsnews_top_mentionsMost-mentioned tickers in the news with their sentiment tilt, a market-attention proxy. Query: date_range (default today), sector (optional). Returns {date_range, sector, mentions[]}.
GET/api/v3/news/sentiment_history/{ticker}news_sentiment_historyDaily aggregated news sentiment for one company from 2000: mean event sentiment (ess_mean, -1 to +1), event count and mean relevance per day. Query: start (YYYY-MM-DD, default one year before end), end (YYYY-MM-DD, default today), min_relevance (0–100, default 70; 90+ means the story is about the company), entity (exact entity-name override), limit (1–10000, default 400). Returns {ticker, entity_names[], start, end, min_relevance, n, rows[], identity, identity_verified, source}.

Analysts

MethodPathMCP toolDescription
GET/api/v3/intel/analyst_consensus/{ticker}intel_analyst_consensusConsensus rating and price-target band. consensus carries rating_label (Strong Buy to Strong Sell), rating_score (1 = Strong Buy, 5 = Strong Sell), the five bucket counts, total_analysts and price_target_avg/_high/_low/_count. When the band comes from a source's own summary, price_target_avg is that source's mean target, not a mean of its mean, high and low. price_target_count_basis says what price_target_count counts: rating_actions or news_rating_actions (actions carrying a target), or summary_fields (the source's low, mean and high, so 3, never a number of analysts); null when there are no targets. price_target_analysts is the number of analysts behind the targets when the source says (for rating actions, the number of distinct firms), otherwise null. pt_band_source_status names the fallback source of the band (fallback_price_target, news_rating_actions or free_quote_scrape) or says why there is none. recent_actions[] (firm, analyst, rating and target from/to) comes only from the ratings calendar's original feed, which is retired, so it is currently always empty; that does not mean no analyst acted. recent_actions_source_status says why the list is what it is: calendar_answered, calendar_error, source_retired or source_not_configured. For rating actions use news/ratings below or the ratings calendar. Query: recent_action_limit (1–50, default 10; caps recent_actions). 1 h cache.
GET/api/v3/news/ratingsnews_ratingsAnalyst rating actions: upgrades, downgrades and initiations, history back to 2022-04-08. Query: tickers (comma-separated), rating_type (upgrade|downgrade|initiation), date_range, items (1–50, default 50), page (1–50, default 1). Returns {tickers, rating_type, date_range, items[], n}.

The ratings calendar, GET /api/v3/intel/calendar/ratings on Macro, Rates & FX, reads the same live ratings feed as news/ratings and adds each action's price-target move (action_pt), derived from the prior and current targets, with action and date filters. Until 2026-09-25 it served an archive that ended on 2026-06-26.

Social attention

MethodPathMCP toolDescription
GET/api/v3/intel/twitter/{ticker}intel_twitterDaily Twitter follower count for one ticker. Each item has ticker, date, followers and pct_change (weekly percent change); there is no mention count. While the upstream dataset returns no rows for any ticker, the route answers 503 with error_code: "upstream_dataset_empty" and Retry-After: 86400, not billed; for retail attention use intel/wsb on Alt-Data. Query: limit (days, 1–365, default 60). Returns {ticker, items[], count, source}.

Coverage and freshness notes.

  • A filter a route does not take is refused, never dropped. On every /api/v3/news/*, /api/v3/intel/news_*, /api/v3/news_crypto/* and /api/v3/news_forex/* route, a non-blank ticker, tickers, symbol, symbols, sector, sectors, industry, topic or topics that the route does not declare (and, on news_forex, pair, pairs, currency or currencies) answers 422 with error: "unsupported_filter", not billed. detail names the parameter or route to use instead, unsupported lists the refused names and accepted the route's own parameters. Before this, such a filter was silently dropped and the unfiltered answer was served as if filtered. Any other unknown parameter is still ignored.
  • Newswire routes are read-through caches with short lifetimes (30 s for alerts, 60 s for news/latest, 90 s for news/summary, 120 s for intel/news_headlines, up to 10 minutes for rollups), so the same call inside that window returns the same payload.
  • When the news feed fails and returns nothing, the /api/v3/news/* routes answer 503 with error: "upstream_unavailable", not billed, instead of a 200 with an empty list. error_code names the failure (upstream_quota_exhausted, upstream_http_error, upstream_not_configured and so on), upstream_error summarises it, and Retry-After says when to retry. The body has no items field. A feed that answered with nothing is still a 200 with an empty list, and a partial failure keeps its rows beside a vendor_error block. news/summary refuses this way when its sub-calls come back empty while the feed's quota is exhausted. When the feed is out of quota and states when its quota resets, upstream_error adds quota_resets_at (UTC) and quota_resets_at_basis (the feed names no time zone; its time is read as New York time), and the body adds retry_after_basis: "firm_recheck": Retry-After is when Wealthnow next checks the feed, within the hour, not when the quota returns. Until quota_resets_at, or a plan change at the source, expect the same refusal.
  • sentiment_history stitches a news-analytics archive (2000 to 2025-12-31) with the live feed from 2026. It keys the archive by the resolved company's name, so identity_verified is always false; if the name cannot be resolved you get error: "entity_unmatched" and can pass entity to override. With no matching rows the response carries warning: "no_rows". When the archive or the live feed cannot be read, it answers 503 with error: "upstream_unavailable" and error_code: "warehouse_read_failed", not billed, never an empty series.
  • The rating-actions feed behind recent_actions on analyst_consensus is retired (no data after 2026-06-30). recent_actions is empty, recent_actions_source_status is source_retired, and the price-target band comes from the fallback sources named in pt_band_source_status. news/ratings and, since 2026-09-25, the ratings calendar read a different, live feed; use them for rating actions.
  • The upstream Twitter dataset returned no rows for any ticker when checked on 2026-07-02 and 2026-09-24, and the route has no fallback source. While that lasts, intel/twitter answers 503 upstream_dataset_empty rather than an empty list. It does not mean the ticker had no followers or attention.

Examples

Example 1: One call for a ticker's news (bash)

Shell
curl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v3/news/summary/AAPL" # Response:# {#   "ok": true,#   "timestamp": "2026-09-24T14:05:11Z",#   "ticker": "AAPL",#   "recent_news": [#     {#       "title": "Apple shares rise after supplier raises its outlook",#       "text": "Shares of Apple rose after ...",#       "news_url": "https://...",#       "source_name": "...",#       "date": "Thu, 24 Sep 2026 09:41:00 -0400",#       "sentiment": "Positive",#       "tickers": ["AAPL"]#     }#   ],#   "sentiment_stats": { ... },   # 7-day daily rollup, same shape as news/sentiment_stats#   "trending": [ ... ],#   "events": [ ... ],            # 7-day structured events#   "analyst_actions": [ ... ],   # 7-day upgrades / downgrades / initiations#   "news_count_24h": 18# }

Example 2: Market-wide headlines (bash)

intel/news_headlines is the market-wide wire. Leave ticker off for a market sweep.

Shell
curl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \  "https://firm.wealthnow.io/api/v3/intel/news_headlines?limit=10" # Response:# {#   "ok": true,#   "timestamp": "2026-09-24T14:06:02Z",#   "ticker": null,#   "items": [#     {#       "headline": "Treasury yields climb ahead of the jobs report",#       "publisher": "...",#       "created_at": "2026-09-24T14:04:37Z",#       "tickers": [],#       "is_major": true,#       "sentiment": "neutral",#       "tags": []#     }#   ],#   "count": 10,#   "as_of": "2026-09-24T14:06:02Z",#   "source": "vendor:options-flow"# }

Example 3: Filtered search and daily sentiment (Python)

Python
import os, requests HEADERS = {"Authorization": f"Bearer {os.environ['WEALTHNOW_API_KEY']}"}BASE = "https://firm.wealthnow.io" # Negative earnings coverage on two names over the last weekr = requests.get(    f"{BASE}/api/v3/news/ticker_news",    params={"tickers": "NVDA,AMD", "topic": "earnings",            "sentiment": "negative", "date_range": "last7days", "items": 20},    headers=HEADERS, timeout=30,)r.raise_for_status()data = r.json()  # {"ok": true, "timestamp": ..., "tickers": ["NVDA", "AMD"], "items": [...], "n": 20}for item in data["items"][:5]:    print(item["date"], item["source_name"], item["title"]) # Daily sentiment for one ticker: outer keys are dates, inner keys are tickersr = requests.get(    f"{BASE}/api/v3/news/sentiment_stats",    params={"ticker": "NVDA", "date_range": "last7days"},    headers=HEADERS, timeout=30,)r.raise_for_status()stats = r.json()["stats"]# stats["data"] == {"2026-09-23": {"NVDA": {"Positive": 14, "Negative": 3,#                                           "Neutral": 9, "sentiment_score": 0.42}}, ...}for day, by_ticker in sorted(stats.get("data", {}).items()):    row = by_ticker.get("NVDA")    if row:        print(day, row["sentiment_score"])

Example 4: Daily sentiment through the 2008 crisis (Python)

Python
import os, requests r = requests.get(    "https://firm.wealthnow.io/api/v3/news/sentiment_history/MSFT",    params={"start": "2008-01-01", "end": "2009-12-31", "min_relevance": 90, "limit": 1000},    headers={"Authorization": f"Bearer {os.environ['WEALTHNOW_API_KEY']}"},    timeout=60,)r.raise_for_status()data = r.json()# {#   "ok": true,#   "ticker": "MSFT",#   "entity_names": ["MICROSOFT CORP"],#   "start": "2008-01-01", "end": "2009-12-31",#   "min_relevance": 90.0,#   "n": 498,#   "rows": [{"date": "2008-01-02", "ess_mean": 0.21, "n_events": 12, "relevance_mean": 97.5}, ...],#   "identity": {...},#   "identity_verified": false,#   "source": "warehouse:news-analytics-archive"# }worst = min(data["rows"], key=lambda row: row["ess_mean"])print("Most negative day:", worst["date"], worst["ess_mean"])

Example 5: Analyst consensus and recent rating actions (Python)

recent_actions on analyst_consensus is empty because its source feed is retired (recent_actions_source_status: "source_retired"), so read rating actions from news/ratings.

Python
import os, requests HEADERS = {"Authorization": f"Bearer {os.environ['WEALTHNOW_API_KEY']}"}BASE = "https://firm.wealthnow.io" r = requests.get(f"{BASE}/api/v3/intel/analyst_consensus/AAPL", headers=HEADERS, timeout=30)r.raise_for_status()data = r.json()  # envelope: {"ok": true, "timestamp": "...", "consensus": {...}, "pt_band_source_status": "...", ...}c = data["consensus"]print(f"{c['rating_label']} (score {c['rating_score']}, {c['total_analysts']} analysts)")print(f"Price target {c['price_target_low']} to {c['price_target_high']}, "      f"avg {c['price_target_avg']}, source: {data['pt_band_source_status']}") r = requests.get(    f"{BASE}/api/v3/news/ratings",    params={"tickers": "AAPL", "date_range": "last30days", "items": 5},    headers=HEADERS, timeout=30,)r.raise_for_status()for action in r.json()["items"]:    print(action)