SentiSense is a read-only financial intelligence API: stock prices, insider/politician trading, institutional flows, AI insights, and news sentiment. No trading, no purchases, no write operations. Free tier available.
Base URL: https://app.sentisense.ai Website: https://sentisense.ai ClawHub Skill: clawhub.ai/TheSentiTrader/sentisense API Docs: https://sentisense.ai/docs/api/ Authentication: API key via X-SentiSense-API-Key header. Get a free key at https://app.sentisense.ai/get-api-key SDKs (optional): Python | Node.js -- source on GitHub. As an AI agent, you're encouraged to call the REST API directly with curl/fetch rather than installing packages.
This skill is an educational data interface to SentiSense's read-only Data API. Output is informational only. It is not investment advice, not a personalized recommendation, and not a solicitation to buy or sell any security. The user is responsible for their own decisions. Use of the API and this skill is subject to the API Terms of Service and Terms of Service.
bash
# Include API key in header
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/..."
Identify your client. Send a User-Agent naming your agent runtime and this skill, for
example OpenClaw/1.4 (sentisense) or ClaudeCode/2.1 (sentisense). Substitute your own runtime and
version if neither matches. You can also volunteer what your agent is called by adding an
agent/<your-agent-name> token inside the same parentheses, as in
OpenClaw/1.4 (sentisense; agent/research-desk). All of it is optional, and it is what tells
us this skill has real integrations behind it, so it gets prioritized and you get notice before it
changes.
python
import os
from sentisense import SentiSenseClient
client = SentiSenseClient(api_key=os.environ["SENTISENSE_API_KEY"])
All API endpoints require an API key. Get one free at https://app.sentisense.ai/get-api-key; the same page is where you manage, rotate, and revoke your keys later, from your account settings at app.sentisense.ai.
The REST recipe in this file is the primary path. A maintained command-line client is available as the separate sentisense-cli skill for hosts that prefer one.
BadgeMeaningPublicAvailable on all tiers (Free and PRO)Public (preview)Free gets limited preview; PRO gets full dataQuota-gatedConsumes monthly quota (Free: limited, PRO: unlimited)**Discovery (no quota cost)**API key required (identity/abuse tracking), but the call does not burn your monthly quota. Rate-limit-per-minute still applies. Used for lightweight metadata endpoints like /stocks/with-kpis and /stocks/{ticker}/kpis/types.PRO onlyRequires PRO subscription
TierRequests/MonthRateFree1,00030 requests/minutePRO ($15/mo)Unlimited300 requests/minutePro MaxUnlimited1,500 requests/minuteData License (Essentials, Premium)Unlimited2,000 requests/minute
Pro Max and the Data License plans include every PRO feature; the API reports their tier as PRO.
Endpoints that take a {ticker} path parameter accept the canonical primary ticker for each company. For dual-class share companies, the API also accepts the secondary class as an alias and resolves it server-side, so you can pass whichever ticker your data source provides.
You passResolves toReasonGOOG``GOOGLAlphabet Class C resolves to Class ABRK.A, BRK-A, BRKA``BRK.BBerkshire Class A resolves to Class BBRK-B, BRKB``BRK.BPunctuation variants normalized
Aliasing applies to research endpoints (analyst, KPIs, insights, insider, institutional holders, politicians filings, options). Quote and chart endpoints leave the ticker as-is, since market-data providers handle their own symbology. Tickers are case-insensitive. News Corp ( NWSA/ NWS) and Fox ( FOXA/ FOX) are NOT aliased to each other (each class is tracked separately).
Cross-reference insider trading, institutional flows, and politician trades to follow where the smart money is moving. High-conviction signals come from convergence across all three.
GET /api/v1/insider/activity for market-wide insider buying/sellingGET /api/v1/institutional/flows for quarterly institutional positioning (optional reportDate; omit for the latest quarter)GET /api/v1/politicians/activity for congressional STOCK Act tradesGET /api/v1/insights/stock/{ticker} for AI signals that combine these data sourcesAlert when sentiment shifts for your stocks. Track news volume, social mentions, and baseline deviations.
GET /api/v2/metrics/entity/{ticker}/metric/sentisense for the SentiSense Score time series (prefer it over sentiment; see the metric notes below)GET /api/v2/metrics/entity/{ticker}/baselines/sentiment for anomaly detection against historical and peer baselinesGET /api/v1/documents/ticker/{ticker} for the underlying news and social posts driving the shiftTrack what Congress is buying before it moves. Filter by party, chamber, or individual politician. Check if corporate insiders agree.
GET /api/v1/politicians/activity for recent congressional trades across all membersGET /api/v1/politicians/member/{slug} for individual politician profiles and trade historyGET /api/v1/insider/trades/{ticker} to cross-reference with corporate insider activity on the same stockGenerate stock research reports by combining multiple data signals into a single analysis.
GET /api/v1/stocks/{ticker}/ai-summary?depth=deep for the full AI analysis reportGET /api/v1/insights/stock/{ticker} for AI-generated stock signalsGET /api/v1/stocks/fundamentals?ticker={ticker} for a single period of financial statement dataGET /api/v1/stocks/fundamentals/history?ticker={ticker}&timeframe=annual&limit=10 for multi-year revenue, margin, and free-cash-flow trend to support valuation workGET /api/v1/documents/ticker/{ticker} for recent news contextPosition ahead of earnings instead of reacting to them. Pull the forward calendar, intersect it with a watchlist, and pre-load sentiment and smart-money context for the companies reporting soon.
GET /api/v1/calendar/earnings?week=next for who reports next week (or ?from=&to= for a custom window)GET /api/v1/calendar/earnings?ticker={ticker} for a single name's next report date and consensus EPS (on a FREE key this searches only the current Monday-to-Sunday week; see the Calendar section)GET /api/v2/metrics/entity/{ticker}/metric/sentisense to gauge positioning into the printGET /api/v1/insider/trades/{ticker} to see if insiders moved ahead of the dateMarket overview combining prices, sentiment, and top signals.
GET /api/v1/stocks/market-status to check if the market is openGET /api/v1/market-summary for AI-generated market headline and analysisGET /api/v1/insights/market for the top market-moving signals right nowGET /api/v1/stocks/prices?tickers=SPY,QQQ,IWM,DIA for index trackingFilter the whole tracked universe on the SentiSense Score and attention in the same query as analyst consensus, technicals and price. The differentiated screens are the disagreements: crowd bullish where the street is not, price below its 200-day while the Score is rising.
GET /api/v1/screener/fields once at startup for the filterable field catalog (stock and ETF), then build filters from itGET /api/v1/screener/screens for 28 curated screens, each with a plan you can execute as-isPOST /api/v1/screener/execute to run a plan against the stock universe (or a tickers watchlist)POST /api/v1/screener/etfs/execute for the same against the ETF universeWhich way the market's tone leans, and how widely it's shared. Daily snapshots.
GET /api/v1/sentiment/sectors for the 11 GICS sectors vs the market's own tone ( consensusVsMarket + "Hotter/Cooler than market" labels; market-relative because news tone skews positive as a genre)GET /api/v1/sentiment/breadth for the bullish/neutral/bearish share of ~1,000 covered stocks (the sentiment advance/decline line; netBreadth in points, stock- and mention-weighted)GET /api/v1/trackers/sentiment-leaderboard for the most bullish and bearish stocks ranked by their 30-day SentiSense Score, with a minimum-mention confidence floor (each row also carries the 7-day Score and raw tone polarity, which do not set the order)GET /api/v1/trackers/sentiment-movers for the biggest SentiSense Score shifts, improving and deteriorating, ranked by the 7-day average Score minus the 30-day average (a row with no Score change falls back to its tone change)GET /api/v1/stocks/market-status first to check if the market is openGET /api/v1/institutional/quarters before the institutional endpoints that need a reportDate to get valid values ( /flows does not need one; omit it for the latest quarter){isPreview, previewReason, data}. Always access response["data"] (or response.data). On a preview (FREE) list response a totalCount field is also present: the number of items in the full PRO dataset, so you can show "showing N of totalCount". A preview is a slice, not the window. When isPreview is true and totalCount is larger than the rows returned, those rows are the newest or top N only: label them ("newest 5 of 61 trades, free preview") and never infer absence from them. No "zero insider buying", "no congressional activity", "not scheduled" or "no unusual contracts" from a slicelookbackDays (1-365) on insider and politician endpoints to control the time windowreportDate for institutional endpoints. When you pass one, fetch it from /quarters first; quarters change as new SEC filings come in. ( /flows does not require one: omit it for the latest quarter, or pass one for a specific quarter.)response["data"] first. All PRO-gated endpoints use the {isPreview, previewReason, data} wrapper, and some Free ones do too ( /stocks/{ticker}/sentiment wraps on every tier), so let each endpoint's own Response line decide rather than inferring the shape from the tier/api/v1/entity-metrics/* for metrics. These are RETIRED (return 410 Gone). Use /api/v2/metrics/ insteadsource parameter is case-insensitive. news, NEWS, News all workDo not hallucinate these. They are not part of the SentiSense API:
/api/v1/options/flow or /api/v1/dark-pool: these exact paths do not exist. For end-of-day options analytics (IV rank, put/call percentile, 25-delta skew, open-interest walls, max pain, unusual-by-volume contracts) use the Options Intelligence endpoints instead: /api/v1/options/overview and /api/v1/stocks/{ticker}/options/summary. We do not attribute tick-level order flow (no buy/sell aggressor tagging) and we have no dark-pool data/api/v1/earnings as a root: the only paths under it are /api/v1/earnings/recent (which covered companies already reported in a recent window), /api/v1/earnings/ranked (the importance-ranked view of recent reporters and upcoming reports) and /api/v1/earnings/statistics (market-wide beat rate joined to what the market did next). For the forward calendar use /api/v1/calendar/earnings; for a company's per-quarter earnings analysis report use /api/v1/stocks/{ticker}/earnings-summaries; for reported financials use /api/v1/stocks/fundamentals (single period) or /api/v1/stocks/fundamentals/history (multi-period trend, up to 40 quarters or 20 years)/api/v1/alerts or /api/v1/notifications: alerts are user-facing only, not available via API/api/v1/chat or /api/v1/ask: the AI chat is not accessible via API/api/v2/sentiment: the correct path is /api/v2/metrics/entity/{id}/metric/sentiment/api/v1/congress or /api/v1/congressional: the correct path is /api/v1/politicians/api/v1/screener/plan and /api/v1/screener/plans: there is no natural-language screen planner and no saved-screen store on the public API. Build the plan object yourself and post it to /api/v1/screener/execute, or execute one of the curated plans from /api/v1/screener/screens/api/v1/stocks)#Latest stock price, 15-minute delayed. Public.
ParamTypeRequiredDescriptiontickerstringYesStock ticker (e.g., AAPL)bash
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/price?ticker=AAPL"
Response: { ticker, currentPrice, change, changePercent, previousClose, volume, timestamp, priceAsOf?, expiresEpochSecond, extendedHours?, listingStatus?, delistedDate?, delistingReason? }.
A delisted symbol returns its last trade price, not an error, and listingStatus is what marks that price as frozen. The three listing fields are present only when the symbol is delisted or pending delisting, and absent otherwise. listingStatus is "DELISTED" or "PENDING_DELISTING"; delistedDate is the ISO date trading stopped; delistingReason is one of acquired, take_private, bankruptcy, exchange_rule, merged. On a "DELISTED" symbol the price, change, and change percent never advance again, so do not render them as a current tick.
Prices are delayed 15 minutes. This applies to every price on this API, in every session, including the extendedHours values below. Do not present these quotes as live, and do not use them for execution or for any decision that turns on the current tick.
Read priceAsOf for freshness: it is when the market data behind currentPrice is actually from, in epoch milliseconds. Do not use timestamp for this. timestamp is when the response was served, so it tracks the current clock no matter how old the value is. priceAsOf is omitted outside regular hours and whenever the upstream data carries no time of its own, so treat an absent priceAsOf as unknown age, not as fresh, and fall back to assuming the 15 minutes.
currentPrice is always the regular-session price: the most recent regular-session value during RTH (09:30 to 16:00 ET), and the most recent regular-session close otherwise. The optional extendedHours field is present whenever there is an extended-hours price to show, which is pre-market (from 04:00 ET) and from the 16:00 ET close until the next pre-market opens, weekends included: once after-hours trading stops at 20:00 ET the last print is carried forward rather than dropped. It is absent during regular hours and for a ticker that did not trade outside them. It carries { session: "pre" | "post", price, change, changePercent }, where change / changePercent are computed vs currentPrice.
Batch latest prices, 15-minute delayed (see /price above). Public. Returns a JSON array; each element has the same shape as /price (including a ticker field, an optional extendedHours object, and the optional listingStatus / delistedDate / delistingReason fields), so check each element for a frozen price rather than assuming a batch is uniformly live.
ParamTypeRequiredDescriptiontickersstringYesComma-separated (e.g., AAPL,TSLA,NVDA)
Historical OHLCV chart data. Public.
ParamTypeRequiredDescriptiontickerstringYesStock tickertimeframestringNo1D, 5D, 1W, 1M, 3M, 6M, 1Y, 5Y, 10Y, MAX (default: 1M)
MAX returns a stock's full available history, up to 26 years (AAPL: 320 monthly bars back to
1999). Granularity scales with the range: intraday for 1D through 1M (5-minute for 1D,
15-minute for 5D, 30-minute for 1W, hourly for 1M), daily for 3M through 1Y, weekly for
5Y/ 10Y, monthly for MAX. Ranges of 10Y and MAX are adjusted for both splits and
dividends so the series is comparable end to end; shorter ranges (through 5Y) are split-adjusted
only, so the two bases differ on the same historical date by roughly the dividends paid since.
volume is on the same adjusted basis as the prices in every range (pre-split bars report shares
in today's share count), so the volume series has no split cliff either. Every bar carries
adjusted: true to mark that basis. Expect an old bar on a heavily-split stock to report a much
larger share count than a recent one: AAPL has split 28-for-1 since 2013, so one share of 2008 is
28 shares now and its raw turnover is counted 28 times over. On the monthly series that puts a 2008
bar near 24 billion shares against roughly 1 billion for a recent month. That is the restatement,
not an error.
10Y and MAX may answer 202 Accepted with an empty array and a Retry-After header, meaning
that stock's deep history is still being assembled; retry and you get the full series. A 200
always carries the range you asked for, never a silently shortened one. An unrecognized
timeframe value answers 400 with an invalid_timeframe error naming the valid values.
Each bar includes timestamp (Unix ms), date, open, high, low, close, volume, adjusted (always true), and session. The session field is pre (04:00 to 09:30 ET), regular (09:30 to 16:00 ET), or post (16:00 to 20:00 ET) for intraday timeframes ( 1D, 5D, 1W, 1M); it is null for daily, weekly, and monthly bars ( 3M and longer) that span whole sessions. The 1M timeframe is filtered to regular-session bars only.
List all tracked ticker symbols. Public.
All stocks with company name, KB entity ID, URL slug, and precomputed socialDominance ( { value, rank, percentile }, daily refresh, null when no signal). Public.
Example: sort the universe by share of voice without any second request, or filter by socialDominance.rank <= 50 for the top-50 most discussed names.
Popular stock tickers. Public.
Popular stocks with company details. Public. Rows carry the same keys as /detailed. Check socialDominance before you sort or filter this list by share of voice: where it is null on a row, read it from /detailed by ticker.
Company logo URLs. Public. GET a returned URL to receive the image bytes; no API key is needed for the image fetch itself. Treat the URLs as refreshable rather than permanent: brand assets are periodically refreshed, so re-read them from this endpoint instead of storing them long term.
ParamTypeRequiredDescriptiontickersstringYesComma-separated tickers (max 600)
Company profiles with branding, industry, and market cap; sector when available (often absent). Public.
ParamTypeRequiredDescriptiontickersstringYesComma-separated tickers
Company profile (CEO, sector, industry). Public.
Also carries listingStatus, delistedDate and delistingReason when the symbol is delisted or pending delisting. All three are absent for a normally listed symbol. Values match /price above: listingStatus is "DELISTED" or "PENDING_DELISTING", delistedDate is the ISO date trading stopped, delistingReason is one of acquired, take_private, bankruptcy, exchange_rule, merged.
For a tracked ETF ticker, the profile may also carry imageUrl, a square presentation image for the fund. It is the issuer's mark rather than the individual fund's, so every fund in a family shares one image, and it matches the imageUrl returned by the /etfs endpoints. It is square like logoUrl and iconUrl, so the same avatar slot renders a stock and an ETF, but it is a first-party asset rather than a vendor branding mark and is returned as a direct URL. It is absent for issuers we hold no image for.
Peer/similar stocks. Public.
ParamTypeRequiredDefaultDescriptionlimitintNo5Max results
Response: bare array of { symbol, name, price, changePercent }. The key is symbol, not ticker, and the array can hold fewer than limit entries.
One-call sentiment picture for a stock: the SentiSense Score with its 30-day regime, where the conversation is happening by source, and what is driving it. Public. Quota-gated when called with a key.
This endpoint also answers without an API key, and returns the same full payload either way. The tradeoff is real in both directions: a keyed call is attributed to your account but spends monthly quota and per-minute rate limit, while a keyless call costs you neither and is not attributed. Send the key when you want the usage on your account; either way the data is identical.
Response: { isPreview, previewReason, data }. Everything below lives under data, which carries ticker, companyName, asOf, then the fields in the table. This endpoint is Free but still uses the wrapper ( isPreview is false and previewReason is null on every tier), so unwrap first: reading sentisenseScore off the root returns nothing, and the full path is data.sentisenseScore.
Field (under data)TypeDescriptionsentisenseScorenumber or nullToday's Score (0-centered composite of sentiment and mentions, unbounded). Null until today's reading lands, see the note belowsentisenseScoreAvg30dnumber30-day average, the stable regime figuresentisenseScoreDelta30dnumberChange over 30 daysscoreLabelstringSeven-band label of the 30-day averagedirectionstringBullish, Neutral or Bearish, from the 30-day averagelatestDirectionstring or nullSame three bands, from today's read. Null in lockstep with sentisenseScore``trendstringUP, DOWN or FLAT``scoreSparklinenumber[]Daily Score seriesmentions / mentionsAvg30dnumberMention volume of the latest New York daily bucket with data (today's once it lands, otherwise an earlier day; narrative names which), and the 30-day daily averagesocialDominancenumberLatest share of voice, as a fraction ( 0.021 = 2.1%)bySource[]arrayPer-source tone, loudest first: source ( News, Reddit, X, YouTube, Hacker News, Substack), direction, mentionShare (whole-number percent; rounding can make the array sum to 99 or 101 rather than exactly 100), value (per-source polarity, -1 to +1)relatedTickers[]arrayCurated peers: ticker, name``drivers[]arrayTop story drivers: title, tone (-1 to +1)narrativestringPlain-language summary of why the Score sits where it doesfaq[]arrayquestion / answer pairs for the common asks on this ticker
Use this when you want the headline read in one call. Use GET /api/v2/metrics/entity/{ticker}/metric/sentisense instead when you need the Score as a time series over a specific window. Returns 404 when the ticker has no sentiment coverage.
sentisenseScore and latestDirection are today's reading, and are null until the day's first analytics run lands (mid-morning ET, later at weekends). Poll before that and every ticker returns null for these two, which is a timing state and not an outage. The rest of the response is unaffected: scoreLabel, direction and sentisenseScoreAvg30d are all computed from the 30-day average, so prefer those when you need a headline that is always present. A null here means "no reading yet", never a Score of zero. A measured 0.0 is served as 0.0, so do not coerce null to 0, and do not infer absence by thresholding the 30-day average, which would suppress genuine neutrals.
Aggregate metrics such as sentiment and mention counts incorporate signals from sources that are not individually retrievable as documents, so document counts from the Documents API are not a complete audit trail of a score.
Via the MCP connector this same picture comes back from the
get_stock_snapshottool rather than a separate sentiment tool.
Related ontology entities (CEO, products, partners). Public. Each entry carries a urlSlug (e.g. Tim-Cook) that plugs into the Metrics API {entityId} parameter. It is a flat list: for the relationship behind each link, use the graph endpoint below.
One company's neighborhood in the SentiSense ontology as a typed graph: the people, products, product families, peer companies and organizations the knowledge base connects to that ticker, plus the named relationship between each pair. Public (API key required). One ticker per call; there is no listing or enumeration form.
ParamTypeRequiredDefaultDescriptiondepthintegerNo1``1 or 2. 1 returns the company's own people, products and peers; 2 walks one hop further, which is how an organization behind a person appears. Anything else returns 400 invalid_depth. Send it explicitly so the walk you describe is the walk you asked forcapintegerNo75``1 to 200, the maximum number of non-root nodes returned. Anything else returns 400 invalid_cap. Send it explicitly for the same reason
Response: a flat object, no {isPreview, data} wrapper.
FieldTypeNotestickerstringThe normalized tickerrootstringThe root company's slug. The root is also the first entry in nodes``depth, capintegerThe values the walk was asked for, echoed back. depth is what you requested, not how far the walk reachedtruncatedbooleantrue when cap cut the walk short. The survivors are ordered by node type then name, not by importance, so a truncated response can drop people and products while keeping peerscountsobject{nodes, edges, byType}, where byType maps a node type to how many of it came backomittedintegerNodes left out for carrying no slug, and so not addressable. Normally 0``groupsobjectpeople, products, productFamilies, peers, organizations, publishers, topics. Every one is a list of slugs except productFamilies, which is a list of {family, members}. A slug is the same handle the Metrics API takes, so you can query one straight from groups; join it to nodes when you need its displayName or type``nodesarray{slug, displayName, type}. type is uppercase ( COMPANY, PERSON, PRODUCT_OR_SERVICE, ORGANIZATION, PUBLISHER, TOPIC), and slug is the Metrics API {entityId} handleedgesarray{source, target, type, direction, properties}, both ends slugs. type is one of LEADS, FOUNDED, PRODUCT_OF, VARIANT_OF, PEER, OWNS, SUBSIDIARY_OF, SUBTOPIC_OF, BELONGS_TO, AFFILIATED_WITH. direction is DIRECTED or BIDIRECTIONAL; on a BIDIRECTIONAL edge the order carries no meaning. properties is a flat string map and is often empty
An unknown or unlisted ticker returns 404 entity_not_found with up to three suggestions, which is a different answer from /entities, where an unknown ticker returns 200 []. The response carries no sentiment, Score or mention counts: fetch those per handle from the Metrics API.
publishers and topics are part of the response shape but are not reachable from a company root today, so treat an empty list there as the expected state rather than as missing theme coverage.
AI-generated stock analysis report. PRO (Free: depth=basic unlimited, depth=deep limited to 10/month). depth=basic returns a preheader summary. depth=deep returns a full multi-section report. Exhausting the depth=deep monthly view allowance returns 429 with {error: "quota_exceeded", message, ...}, the same contract as every other quota-gated endpoint: message says when the allowance resets (the start of next month) and links PRO, and the response has no Retry-After header.
ParamTypeRequiredDefaultDescriptiondepthstringNobasic``basic or deep
Response: flat object (no {isPreview, data} wrapper).
FieldTypeNotestickerstringcompanyNamestringstatusstringREADY, NOT_AVAILABLE, or ERROR``statusReasonstring or nullPresent on NOT_AVAILABLE / ERROR onlyreportTypestringSUMMARY for depth=basic, FULL for depth=deep``versionintegerReport date encoded as yymmdd (e.g. 260520)lastUpdatedlongEpoch millisecondssectionsobjectSection name to {content, directives}. Present on both depths: depth=basic returns a single Executive Summary section, depth=deep returns the full set.sectionOrderstring[]Ordered section keys for rendering. Present on both depths; ["Executive Summary"] on depth=basic.fromCachebooleanWhether this response was served from the report cache. false also covers a report served straight from the packaged knowledge base, so it does not mean the report was regenerated for your call: read freshness from lastUpdated.moatRatinginteger or nullProprietary moat quality score 0-10 (network effects, switching costs, intangibles, cost advantages, efficient scale). Present on depth=deep only. Null if not yet assessed for this ticker.aiDisruptionRiskstring or nullLow, Medium, High, or Critical. Measures AI revenue-displacement exposure. Present on depth=deep only. Null if not yet assessed.
Do not test for the presence of sections to detect a deep report: both depths return it. Branch on reportType ( SUMMARY vs FULL) instead.
Sentiment or mention metrics breakdown by sub-entities. Public.
ParamTypeRequiredDescriptionmetricTypepathYessentiment or mentions``startTimelongYesStart time in epoch msendTimelongYesEnd time in epoch ms
Current market open/closed status. API key required.
Response: { status: "open" | "closed", timestamp: <epoch_ms> }. The timestamp is a numeric epoch milliseconds value (not a string).
Financial statement data. Public.
ParamTypeRequiredDefaultDescriptiontickerstringYes-Stock tickertimeframestringNoquarterly``quarterly or annual``fiscalPeriodstringNo-e.g., Q4``fiscalYearintNo-e.g., 2024
Reporting currency (applies to every fundamentals endpoint): figures are as reported by the
filer, in the filer's own currency, never converted to USD. Foreign ADR filers report in home
currency (SK hynix: KRW, Toyota: JPY, ASML: EUR). The optional reportedCurrency field ("USD",
"KRW", ...) on the response (and on each /fundamentals/history row) names it; when absent the
currency is unknown, not implicitly USD. Never mix these figures with the share price: the price
is the USD ADR price, so for non-USD filers peRatio / psRatio / pbRatio are served as
null on purpose, and you should not recompute them. Same-currency ratios (margins, ROE, ROA,
current ratio, debt/equity) stay valid for all filers.
Trailing-twelve-month valuation snapshot against the latest price. Public. It is not a statement snapshot: for income-statement, balance-sheet and cash-flow lines use /fundamentals or /fundamentals/history.
ParamTypeRequiredDescriptiontickerstringYesStock ticker
Response (flat): { ticker, currentPrice, peTTM, psTTM, epsTTM, revenueTTM, quartersIncluded, available, reason, fetchedAt, reportedCurrency? }. peTTM and psTTM are the latest price over trailing EPS and over trailing revenue per share; quartersIncluded is how many quarters the trailing figures sum (normally 4); fetchedAt is epoch seconds. When available is false, reason says why (no current price, or no trailing earnings data) and the TTM fields are null. reportedCurrency names the currency of epsTTM and revenueTTM ( currentPrice stays USD) and is omitted when unknown; for a non-USD filer peTTM and psTTM are null by design, the same cross-currency rule as above.
Multi-period history of full financial statements (income statement, balance sheet, cash flow), one
entry per fiscal quarter or year, newest first. Use for margin trends, multi-year comparisons, or as
the input to a valuation model. Not the same endpoint as /fundamentals (single period) or
/fundamentals/historical/revenue (income-statement lines only, no balance sheet or cash flow). Public.
ParamTypeRequiredDefaultDescriptiontickerstringYes-Stock tickertimeframestringNoquarterly``quarterly or annual``limitintNo12 quarterly / 10 annualPeriods to return, capped at 40 quarterly / 20 annual
Response includes count (periods actually returned, can be less than limit), reason
(non-null only when periods is empty, e.g. a recent listing), and dataSource (deprecated:
always an empty string, kept for response-shape compatibility, slated for removal).
Earnings and share-count fields (same on /fundamentals). These are reported independently by
the data provider. They are NOT derived from one another and will NOT reconcile arithmetically:
netIncome / weightedAverageSharesDiluted does not reproduce any EPS field, because the provider
computes EPS from its own numerator on its own share basis. Do not "check" our data by dividing
these, and do not present a computed per-share figure as if it were the reported one.
FieldMeaningepsBasicBasic EPS. Always basic, on every source.epsDilutedDiluted EPS. Null when the provider reports no diluted figure.epsEPS as the provider reports it, usually basic. Prefer epsBasic/ epsDiluted, which name their basis.netIncomeConsolidated net income. Not the EPS numerator.bottomLineNetIncomeThe provider's bottom-line income line, which can differ from netIncome in size and in sign. Null means the line was not supplied for that period, not that it equals netIncome.weightedAverageSharesBasicBasic weighted-average shares for the period. Null when not reported.weightedAverageSharesDilutedDiluted weighted-average shares for the period. Null when not reported.sharesOutstandingDeprecated, stops being populated 2026-12-15. Not a period-end count despite the name. Use the weighted-average fields.
Both share fields are averages ACROSS the period, not counts at period end, so neither is a correct
input to a market capitalisation or a book value per share; a share field is null when the provider
reports no count on that basis or a count of zero or below. Income fields are in the filer's reporting
currency (see reportedCurrency), EPS is that currency per share, share fields are a number of
shares. Per-period EPS is served as the provider reports it, and we restate it for a small list of named issuers and nowhere else: where a provider restated a company's share counts for a split but left older rows' EPS on the pre-split basis, and that has been checked against the company's own filing, we divide the EPS on the affected rows by the split ratio and mark each one with epsBasisRepair ( fields, multiplier, splitExecutionDates). Share counts and net income are never changed. epsBasisRepair is null on almost every row, and null means we applied no EPS repair to that row: it is NOT a statement that the row's EPS and share count are on the same basis, since an unlisted issuer, a row that did not qualify, and a row whose split history we could not read all carry null. epsBasisRepair describes per-period EPS only: this repair never changes epsTTM or the other trailing-twelve-month figures, and the marker never describes a trailing adjustment. Trailing figures are assembled separately and whether they carry a split adjustment of their own depends on which source served them. For a small list of recently listed companies, quarterly history also includes a pre-IPO quarter the company filed only as the prior-year comparison column of a later filing, usually its first 10-Q: that row carries preIpoFiling ( form, accession, filedDate, note) naming the filing, holds the income-statement lines only, and gives way to the provider's own row for the same period once one exists. preIpoFiling is null on every other row.
Available fiscal periods. Public.
ParamTypeRequiredDescriptiontickerstringYesStock ticker
Historical income-statement lines per period: revenue, gross profit, operating income, net income,
and EPS. Response wraps them in dataPoints (not periods like /fundamentals/history), plus
count, dataSource, and reason. For full statements including balance sheet and cash flow,
use /fundamentals/history instead. Public.
ParamTypeRequiredDefaultDescriptiontickerstringYes-Stock tickertimeframestringNoquarterly``quarterly or annual
Short interest data from FINRA. Public.
ParamTypeRequiredDefaultDescriptiontickerstringYes-Stock tickerlimitintNo24Max data points
Float information (shares outstanding, public float). Public.
ParamTypeRequiredDescriptiontickerstringYesStock ticker
Short volume trading data. Public.
ParamTypeRequiredDefaultDescriptiontickerstringYes-Stock tickerlimitintNo90Max data points
Aggregate quote snapshot: latest price (15-minute delayed), today OHLC, 52-week range, market cap, P/E, EPS TTM, dividend yield, 200-day moving average. Single call for detail pages. API key required.
Response: { ticker, currentPrice, change, changePercent, volume, open, dayHigh, dayLow, previousClose, week52High, week52Low, marketCap, peRatio, epsTTM, dividendYield, movingAverage200Day, reportedCurrency, timestamp, extendedHours?, listingStatus?, delistedDate?, delistingReason? } -- all fields except ticker are nullable. currentPrice is always the regular-session price; the optional extendedHours object ( { session, price, change, changePercent }) is present outside regular hours whenever an extended-hours price exists, and session stays "post" while the last after-hours print is carried overnight and through the weekend. movingAverage200Day is null when fewer than 200 trading days of history exist. reportedCurrency ("USD", "EUR", "KRW", ...) names the currency epsTTM is reported in, matching the fundamentals endpoints. Responses carry a private 15 s max-age; the server's own price cache is 30 s, per process.
Null fields are omitted, and foreign filers omit peRatio. A null field is left out of the JSON entirely rather than serialized as null, so do not assume a key is present: read defensively. On foreign ADR filers such as ASML and TM, peRatio is absent, while epsTTM is served in the filer's home currency and reportedCurrency names that currency ( EUR for ASML, JPY for TM, whose epsTTM reads in the thousands beside a USD price near 200). Price fields and dividendYield are served normally. This is the same cross-currency rule as the fundamentals endpoints: the price is the USD ADR price and the filer's earnings are in home currency, so peRatio is withheld rather than computed across two currencies. Always check reportedCurrency before using epsTTM, and do not divide currentPrice by a non-USD epsTTM to fill the gap yourself.
Delisted symbols keep quoting their last trade. listingStatus, delistedDate and delistingReason are present only when the symbol is delisted or pending delisting, and absent otherwise, with the same values as /price. When listingStatus reads "DELISTED", every price field in this payload is frozen at the last trade before delistedDate and nothing else in the response says so.
ETF tickers (e.g. VTI, SPY) return 400 ticker_is_etf from this endpoint. Use GET /api/v1/etfs/{ticker}/quote instead, which returns AUM, expense ratio, NAV, and inception date rather than market cap, P/E, and EPS.
Company-specific KPI time-series. Curated GAAP and non-GAAP metrics from earnings filings: iPhone unit sales, Tesla deliveries, AWS revenue, Netflix paid net adds, etc. PRO (preview) -- Free: metadata only with empty kpis list, PRO: full series. Returns 404 for tickers without curated coverage.
Coverage today: near-complete for the S&P 500 plus an extended universe of 900+ US-listed companies (970 tickers as of 2026-09-09). Use GET /api/v1/stocks/with-kpis to enumerate.
Response wrapper: { isPreview, previewReason, data: CompanyKpis }.
CompanyKpis shape: { ticker, companyName, cik, lastUpdated, kpis: KpiSeries[] }.
KpiSeries shape: { id, name, category, unit, displayFormat, chartType, values: KpiDataPoint[], sourceRef, discontinued, discontinuedNote }. id is a stable per-ticker identifier (e.g. iphone_revenue). category is one of product_revenue, segment_revenue, unit_economics, etc. chartType is bar or line.
KpiDataPoint shape: { period, date, value, isEstimate }. period is the fiscal label (e.g. Q2 FY2026); date is the ISO close date.
Pass ticker, selected KPI IDs and any fetched response to the company-kpi-tracker skill; return a dated card with matched deltas and source and estimate flags.
List every ticker with curated KPI coverage. Sorted alphabetically. Builder discovery: render a supported-tickers page or seed a watchlist without 404-probing one ticker at a time. Discovery (no quota cost) -- API key required for identity/abuse tracking, but the call does not consume your monthly quota. Rate-limit-per-minute still applies.
Response: { count, tickers: KpiCoverageEntry[] } where each entry is { ticker, companyName, lastUpdated, kpiCount }.
python
client = SentiSenseClient(api_key=os.environ["SENTISENSE_API_KEY"])
coverage = client.list_kpi_coverage()
print(f"{coverage.count} tickers covered")
for entry in coverage.tickers[:5]:
print(f" {entry.ticker}: {entry.kpiCount} KPIs (refreshed {entry.lastUpdated})")
Lightweight KPI metadata tuples for a ticker, without the full series payload. Mirrors /api/v1/insights/stock/{ticker}/types. Useful for letting an agent or UI decide what to fetch before committing to the heavy data call. Discovery (no quota cost) -- API key required, no quota burn.
Response: bare array of { id, name, category, chartType }. Returns 404 if the ticker has no curated KPIs.
python
types = client.get_kpi_types("AAPL")
for t in types:
print(f" {t.id} ({t.chartType}): {t.name}")
/api/v1/kb)#Search the SentiSense ontology for the people, companies, products, and organizations SentiSense tracks, and get the handle to query their metrics. Public (API key required).
ParamTypeRequiredDefaultDescriptionqstringYes-Name, alias, ticker, or slug fragment (case-insensitive, minimum 2 characters)typestringNoallcompany, country, etf, organization, person, product, topic``limitintNo10Max results (capped at 25)
Response: array of {name, urlSlug, type, ticker} matches, best first. ticker is null for entities without one. Feed the urlSlug (or ticker) into the Metrics API {entityId} parameter:
text
GET /api/v1/kb/entities/search?q=pelosi -> [{"name": "Nancy Pelosi", "urlSlug": "Nancy-Pelosi", "type": "person", "ticker": null}]
GET /api/v2/metrics/entity/Nancy-Pelosi/metric/sentisense
People, products, and organizations have the same metrics surface as stocks, so this unlocks queries like a politician's mention volume, a CEO's SentiSense Score ( .../entity/Jensen-Huang/metric/sentisense), or crowd sentiment on a product versus its parent ticker.
Curated list of high-profile tracked entities (major CEOs, political figures, the Federal Reserve). Public (API key required). Returns {displayName, type, urlSlug, relatedStock} entries; use as an autocomplete seed list without issuing a search.
/api/v2/metrics)#Time series metrics for stocks and entities: mentions, sentiment, social dominance, and more. The {entityId} path segment accepts a stock ticker (e.g. AAPL) or an entity urlSlug (e.g. Nancy-Pelosi); both are case-insensitive, and a ticker-shaped identifier always means the listed company. Discover handles with GET /api/v1/kb/entities/search?q= or GET /api/v1/stocks/{ticker}/entities. An unknown identifier returns 404 entity_not_found with up to three suggestions.
Which handle to store: the urlSlug, or the ticker for a listed company. It is the only identifier these paths accept. Internal KB ids, in any spelling ( kb/person/65, kb-person-65, p65), are not part of the public API and resolve to nothing. If a rename ever breaks a stored handle, find the entity again by name with GET /api/v1/kb/entities/search?q=.
Every metric type ( mentions, sentiment, sentisense, social_dominance, sentisense_rating, app_review_count, app_rating) is available on the Free tier: no PRO subscription needed. All metrics endpoints are Quota-gated: an API key is required and each request counts against your monthly quota (Free: 1,000 requests/month; PRO: no monthly cap). Per-minute rate limits apply on every tier.
Time series metric data for a stock or entity. Quota-gated -- all metric types ( mentions, sentiment, sentisense, social_dominance, sentisense_rating, app_review_count, app_rating) are available on the Free tier. sentisense_rating is stocks-only and its value is the daily Rating score, 0 to 100, which is the number the letter is banded from and not the percentile; see the SentiSense Rating API section below.
What each metric type means:
mentions -- count of documents that mentioned the entity that day, across news, social and other tracked sources.sentisense -- the SentiSense Score, an unbounded composite of sentiment and attention ( sentisense_score also resolves). Prefer this over sentiment for any bullish-or-bearish read: it weights tone by how actively the name is discussed, so a single post on a quiet day cannot swing it, and each point carries the counts behind it under metricValue.properties (see "Reading direction" below).sentiment -- mean polarity of those documents, a float in [-1, 1], unweighted by volume and therefore thin-sample sensitive. Use it for raw tone, or with mean-by/source for per-source tone.social_dominance -- the entity's share of the day's total conversation.sentisense_rating -- the daily Rating score, 0 to 100 (not the percentile). Stocks only.app_review_count -- count of new Apple App Store reviews for a product's iOS app that day. Products only, and only those with a tracked app.app_rating -- mean star rating (1 to 5) of that day's new App Store reviews. Same coverage as app_review_count.From 2026-09-05, mentions no longer includes App Store reviews. A review is a rating, not chatter, and for review-heavy products the two used to read as one number. The App Store slice itself is unchanged and still appears under distribution/mentions?dimension=source; only the root mentions total stopped summing it. Read review volume from app_review_count instead, and expect a step down in the root series around that date for products with an app (history has been restated, so a long window should be continuous).
ParamTypeRequiredDefaultDescriptionentityIdpathYes-Stock ticker (e.g., AAPL) or entity urlSlug (e.g., Nancy-Pelosi)metricTypepathYes-mentions, sentiment, sentisense, social_dominance, sentisense_rating, app_review_count, app_rating``startTimelongNo7 days agoEpoch millisecondsendTimelongNonowEpoch millisecondsmaxDataPointsintNo-Return at most N of the window's points, unmerged, in ascending order, evenly spaced back from the latest point, which is always included. It caps the points and does not set the window, so pair it with startTime
Response: an array of points ordered ascending by timestamp. Each point exposes a flat value scalar alongside the full metricValue object:
json
[
{
"timestamp": 1780372800000,
"metricType": "SENTIMENT",
"value": 0.42,
"metricValue": { "type": "ValueMetricValue", "valueType": "MEAN", "value": { "value": 0.42 } }
}
]
Read the scalar from the flat value (the polarity for sentiment, the count for mentions). It saves you walking the nested metricValue.value (count metrics) or metricValue.value.value (value metrics), whose depth varies by metric type. A point with no reading omits value. To derive the current reading and its change: points are time-ascending, so the current value is the last point's value, and the change is the last point's value minus the prior point's (or minus the first point's for the whole window). A window with 0 or 1 point has no derivable trend, so widen startTime rather than reporting a change.
Reading direction from a sentisense point. Each Score point carries three counts under metricValue.properties:
json
{ "bull": 48.0, "bear": 17.0, "directional": 65.0 }
bull / bear: mentions that day our models scored bullish / bearish for the entity.directional: bull plus bear, the sample size behind that day's Score.Mention volume is direction-blind: a spike in mentions fires as hard on a crash as on a rally, so never call a name bullish or bearish from volume, or from a sector or rival's read. Settle direction from that entity's own bull against bear, and when the question is "is this spike good or bad news?", read those two counts on the spike day. Sum bull and bear across a window to state a run ("bull-led every day this week, 310 to 140"). Points are daily, one per New York calendar day. The last point is the latest day with data: today's partial bucket once the day's first reading lands, otherwise the last complete day. Compare its timestamp to today's New York date before treating it as a partial day, and do not compare a partial day to full days.
A metric split across a dimension (e.g., mentions or sentiment by source). Quota-gated, available on the Free tier.
Response: { metricType, dimension, distribution, valueType, ... }, where distribution maps each dimension value to a number and is an empty map when there is no data. valueType says what the number is. For count metrics such as mentions it is SHARE_PERCENT: that source's percentage share of the metric's total over the window, summing to about 100. For sentiment it is MEAN: that source's mean polarity over the window, in [-1, 1], the same numbers as mean-by/{dimension}. sentisense has no per-source split and returns an empty map; for where its conversation came from, read distribution/mentions. For "what share of the conversation is News", /api/v1/stocks/{ticker}/sentiment data.bySource[].mentionShare answers the same question over a fixed 30-day window.
ParamTypeRequiredDefaultDescriptionentityIdpathYes-Stock ticker or entity urlSlug``metricTypepathYes-Metric type keydimensionstringYes-Dimension to slice by. Use source; see the /slices note belowstartTimelongNo7 days agoEpoch millisecondsendTimelongNonowEpoch milliseconds
Mean of a metric per dimension value over a time window (e.g., per-source mean sentiment). Quota-gated, available on the Free tier.
ParamTypeRequiredDefaultDescriptionentityIdpathYes-Stock ticker or entity urlSlug``metricTypepathYes-Metric type key (e.g., sentiment)dimensionpathYes-Dimension to group by. Use source; see the /slices note belowstartTimelongNo7 days agoEpoch millisecondsendTimelongNonowEpoch milliseconds
Response: flat map of dimension value to mean, e.g. { "News": 0.37, "Reddit": 0.04, "X": 0.22, "YouTube": 0.25, "Hacker News": -0.57, "Substack": 0.5 }. The keys are display names, title case and possibly containing a space ( Hacker News), not the uppercase source parameter values; distribution uses the same keys. Look them up case-insensitively, or iterate the map, rather than indexing a fixed "NEWS". For sentiment by source, each value is the average of that source's daily mean readings inside the window; a window with no data returns {}. Returns 400 for an unknown metric type or when startTime is after endTime.
Slice keys stored for a metric. Quota-gated, available on the Free tier. Response: array of { metricType, dimension, values, displayName }. It currently returns only { dimension: "type", values: ["root"] }, the marker for the unsliced series, so it is not a guide to what distribution and mean-by accept: pass source to those two. type is not a usable split there (it currently fails with a 500 after a long wait), and an unrecognized dimension returns 400.
Historical and peer baselines for a metric. Quota-gated, available on the Free tier.
/api/v1/rating)#The SentiSense Rating is a daily score from 0 to 100 for a US stock, and the letter grade A to F that bands it. It blends seven independent signal families and reports where the stock sits against every other stock rated that day, less a risk adjustment for each condition it carries. Full methodology: https://sentisense.ai/methodology/#sentisense-rating
Report the letter and the score; the percentile is the rank before penalties. score = percentile - sum(riskAdjustments[].points), each adjustment worth up to 12 points, floored at 10 when fewer than 6 of the 7 dimensions are available and at 0 otherwise, and letter is the band score falls in. Present it as "B, 85.6 out of 100, ranked in the 100th percentile with 14.4 points of risk adjustments". Never quote the percentile as though it were the grade, and never translate a letter into buy, sell, hold, long, short, avoid, or any other trade instruction: the grade does not carry that meaning and the response ships a disclaimer string for you to render alongside it. At most one stock in ten can carry an A, since only the top tenth of ranks reaches 90 before any adjustment, and in practice far fewer do.
Beta: the response shape is stable, but the method is still being tuned and a stock's score can shift between methodologyVersion values. Every response carries a betaNotice string saying so while this holds, on both the rated and the not-rated shape; it disappears when the Beta ends, so treat it as optional.
Not the same object as the SentiSense Score. The Score is the continuous crowd-sentiment number and is one of the seven inputs here; the Rating is the composite grade. Do not use the two names interchangeably.
Letter bands, on the score: A 90 and above, B 70 to 89.9, C 30 to 69.9, D 10 to 29.9, F below 10. The bands are not fixed shares of the market. Dimension weights: fundamentals 20%, crowd sentiment 16%, smart money 16%, technicals 16%, options positioning 12%, analysts 12%, earnings 8%. Fundamentals reads four inputs: trailing operating margin, return on equity, year-over-year revenue growth, and durability, the share of the last 20 fiscal quarters with positive operating income, positive free cash flow and revenue above the same quarter a year earlier.
score, percentile, penaltyPoints and riskAdjustments are returned side by side so you can check the arithmetic. A response reading percentile: 100.0, penaltyPoints: 14.4, riskAdjustments: [{condition: "weak_dimension", points: 2.4}, {condition: "high_leverage", points: 12.0}], score: 85.6, letter: "B" is correct and internally consistent, not a data error; bucketLetter reports the A the rank alone would have given. Most adjustments are graded: 8 of the 12 conditions scale with how far past the threshold the stock sits, up to 12 points, and 4 are flat 12s. Read each cost from riskAdjustments[].points, never from 12 x riskConditions.length.
Recomputed once per trading day at 07:15 Eastern Time on the morning after each session, so the run lands Tuesday through Saturday. Cache on asOf; polling faster than daily returns the same values.
Today's Rating for one stock. Quota-gated, served in full on the Free tier (no PRO cut).
Response is a flat object, no {isPreview, data} wrapper. When the stock was graded: ticker, kbEntityId, rated: true, score (0-100 with one decimal, the headline), letter (the band score falls in, displayed beside it), percentile (0-100, the rank score was built from), penaltyPoints (what the risk adjustments took off, to one decimal), riskAdjustments ( {condition, points} per adjustment, where each cost actually lives), riskConditions (the names that cost more than zero; empty when the stock carries none, in which case score equals percentile), bucketLetter (the band percentile alone would fall in), composite (the pre-rank blend, comparable within a day only), ratedCount (the denominator behind percentile), asOf, methodologyVersion, dimensions, flags, disclaimer.
riskConditions is a closed vocabulary, each worth up to 12 points. Graded (the cost scales, read it from riskAdjustments): thin_coverage (currently 6 points per missing dimension once fewer than 6 of the 7 are available, so 5 dimensions cost 6 and 4 cost 12 while 6 or 7 cost nothing; below 6 it also floors the score at 10), institutional_outflow (scaled by how deep in the bottom quarter of net institutional change), high_leverage (currently 6 points per unit of debt to equity above 2), weak_dimension (weakest available dimension below the 20th percentile, currently 0.6 points per percentile below 20), small_market_cap (graded on a log scale of market capitalization: nothing at 50 billion dollars and above, 10 points at 10 billion, 12 at 2 billion and below; below 10 billion the charge alone keeps the score out of the A band), thin_liquidity (currently under 10 million dollars in the latest session, scaled by the shortfall), extended_price (currently within 5 percent of the 52-week high and more than 25 percent above the 200-day moving average, scaled by the excess above 25 percent), rich_valuation (the trailing price to earnings multiple is high in absolute terms and in the top tail of the day's cross section, scaled by how far into that tail it sits; a multiple we could not establish costs nothing, which covers a company with no trailing profit and a filer reporting in a currency its price is not quoted in). Flat 12: insider_selling, unprofitable (trailing twelve month operating or net margin not positive), no_fundamentals, unseasoned_listing (currently fewer than 250 trading sessions in the past 400 days). Thresholds and graded rates are tuned as calibration data accumulates; the constituents, their maximum and the formula are versioned. Treat an unrecognized value as a condition this client does not know about, costing whatever riskAdjustments says, not as an error.
dimensions always carries all seven rows in a fixed order: crowd, smart_money, options, analysts, fundamentals, earnings, technicals. technicals reads where the price sits versus its own history: distance from its 200-day and 50-day averages, its twelve-month path, and how calm or violent its recent sessions have been, with calmer ranking higher. It is a description of the current trend state, not a forecast, and its raw is the distance from the 200-day average in percent. Each is { key, label, percentile, raw, rawLabel, present }. Branch on present, not on raw != null: smart_money is present with a null raw because it has no single underlying number, and instead carries a subLegs array of { key, label, raw, unit } for inst_13f, insider and congress.
flags holds only the anomaly flags that could be evaluated for this stock, each { key, label, active }, over clustered_insider_selling, institutional_outflow_against_price and unusual_options_flow. The first two are also risk conditions and take points off the score while active, clustered_insider_selling a flat 12 and institutional_outflow_against_price a graded amount; unusual_options_flow is informational only. A flag absent from the array means "not assessable here", which is not the same as active: false, so look flags up by key rather than by position.
A missing dimension counts as the median, the 50th percentile, at its full weight, rather than being dropped with the other weights rescaled, so thin coverage pulls a grade toward the middle instead of lifting it to the top.
Not every stock is rated, and that is a normal 200. A stock is graded only when at least 4 of the 7 dimensions have data and those dimensions carry at least 50 percent of the total weight. Otherwise the response is rated: false with a reason ( not_rated_today, insufficient_dimensions or insufficient_coverage_weight), a presentDimensions list of the dimension keys that did have data, a dimensionsPresent integer count of the same, the seven dimensions rows with present: false on the gaps, an empty flags, and the disclaimer. Those two field names are one transposition apart and only the list is guaranteed: dimensionsPresent is omitted when the run holds no record for the ticker, so read presentDimensions.length when you need a count. On that shape score, letter, percentile, penaltyPoints, riskAdjustments, riskConditions, bucketLetter, composite, ratedCount and methodologyVersion are absent entirely, so check rated before reading any of them. A stock is never given a C by default, so report "not rated" as an absence of evidence, not as a middling grade. ETFs are never rated; thinly covered small caps often are not.
An unknown ticker returns 404 entity_not_found with a hint pointing at GET /api/v1/kb/entities/search?q=. That is a different answer from rated: false.
History: each daily run is stored as the sentisense_rating metric, so GET /api/v2/metrics/entity/{ticker}/metric/sentisense_rating returns the series. The flat value on each point is the score, not the letter and not the percentile; the letter, composite, ratedCount, coverageWeight, dimensionsPresent, methodologyVersion, a dim<Name>Pct / dim<Name>Raw pair per dimension and a flag<Name> boolean ride under metricValue.properties. Points exist only for days the stock was rated, so a gap means "not rated that day".
Screening: the Screener API exposes the letter as SENTISENSE_RATING, a string field over A- F taking IN / NOT_IN, sortable by the underlying score. See the Screener section below.
/api/v1/sentiment)#Market-wide sentiment structure: which way tone leans by sector, and how widely that lean is shared. Both endpoints serve a precomputed daily snapshot, so serving never recomputes and the values move once a day. Both are Quota-gated (API key required, each call counts against your monthly quota), take no parameters, and return their payload flat, with no {isPreview, previewReason, data} wrapper.
Read tone here as market-relative. News and social tone carries a large structural positive skew as a genre, so an absolute sector reading is bullish almost every day and says little on its own. What carries information is a sector's distance from the market's own tone.
The 11 GICS sectors measured against the market's own tone, with the most bullish and most bearish member stock per sector. No parameters.
Response: {schemaVersion, generatedAt, asOf, narrative, marketConsensusRatio, sectors: [...]}. generatedAt is epoch seconds, asOf is the ISO YYYY-MM-DD day the snapshot covers, narrative is a ready-to-print one-line summary, and marketConsensusRatio is the whole covered universe's directional-consensus ratio, the baseline every sector is measured against.
json
{
"schemaVersion": "1.0",
"generatedAt": 1787177768,
"asOf": "2026-08-19",
"narrative": "As of 2026-08-19, Energy runs hottest versus the market's own tone, across 1028 covered US stocks.",
"marketConsensusRatio": 0.3259,
"sectors": [
{
"sector": "Energy",
"meanSentiment": 0.2086, "label": "Bullish",
"meanScore": 4.6723, "scoreLabel": "Neutral",
"consensusRatio": 0.4359, "consensusVsMarket": 0.11,
"consensusLabel": "Hotter than market",
"bullMentions": 844, "bearMentions": 331,
"stockCount": 52, "totalMentions": 339,
"topStock": {"ticker": "APA", "value": 0.9},
"bottomStock": {"ticker": "MUR", "value": -0.4}
}
]
}
Four field notes worth reading before rendering any of it:
consensusVsMarket is the value to rank or color by. It is consensusRatio minus marketConsensusRatio. A negative value means cooler than the market, not bearish; consensusLabel already carries the safe wording ("Hotter than market", "In line with market", "Cooler than market").meanSentiment and meanScore are different scales. The first is polarity on [-1, 1]; the second is the SentiSense Score, open-ended and banded by scoreLabel. Do not compare them or plot them on one axis. consensusRatio is a tone ratio and is not a Score either, so do not run it through the Score bands.stockCount and totalMentions are confidence cues. A sector carrying a handful of covered names is a thin reading; show the count next to the tile.topStock and bottomStock are the sector's most bullish and most bearish member by polarity, each {ticker, value}, ready for a drill-down link.The sentiment analogue of the advance/decline line: across the covered universe, what share of stocks is bullish versus bearish, today and daily back through the backfilled history. No parameters.
Response: {schemaVersion, generatedAt, asOf, minMentions, latest: {...}, series: [...]}. latest is today's bucket, series is the daily history oldest to newest (the stacked distribution chart), and minMentions is the mention floor a stock must clear to be counted at all.
json
{
"schemaVersion": "1.0",
"generatedAt": 1787177768,
"asOf": "2026-08-19",
"minMentions": 5,
"latest": {
"date": "2026-08-19",
"coveredStocks": 459, "totalMentions": 7984,
"bullish": 318, "neutral": 76, "bearish": 65,
"bullishPct": 69.28, "neutralPct": 16.56, "bearishPct": 14.16,
"netBreadth": 55.12,
"bullishMentionPct": 76.32, "neutralMentionPct": 14.4, "bearishMentionPct": 9.28,
"sentimentDispersion": 0.2884
},
"series": [{"date": "2026-07-02", "...": "same shape as latest"}]
}
Every bucket carries the same classification under two weightings, and mixing them is the easy mistake. bullish / neutral / bearish and their *Pct are stock-weighted: one vote per covered stock, the true advance/decline analogue. bullishMentionPct / neutralMentionPct / bearishMentionPct are mention-weighted: the same votes weighted by how much each stock is being talked about. The two diverge when a few heavily discussed names lean against the crowd, which is itself the interesting reading.
netBreadth is bullishPct minus bearishPct, in percentage points on [-100, 100]. It says which way the market leans.sentimentDispersion is the spread of per-stock polarity across that same universe. High means the tape is splitting name by name (a stock-picker's market), low means one shared mood is washing over everything. It says how much the market agrees with itself, which is a different question from which way it leans. Null when fewer than two stocks qualify.coveredStocks is the denominator and it moves day to day with news volume, so compare percentages across days, never raw counts./api/v2/market-mood)#SentiSense's proprietary composite market sentiment index. Combines social sentiment, market direction, risk appetite, social momentum, S&P 500 trend, and options flow signals into a single 0-100 score with sector breakdown. Free (API key required). Free for all tiers, but anonymous calls return 401 api_key_required.
Composite market sentiment score with history and sector breakdown.
ParamTypeRequiredDefaultDescriptiondaysintNo180Days of history to return
Response shape:
json
{
"market": {
"currentScore": 62.88,
"phase": "Optimism",
"weeklyChange": -2.3,
"signals": [
{"key": "social_sentiment", "label": "Social Sentiment", "value": 54.95, "change": -1.2},
{"key": "market_direction", "label": "Market Direction", "value": 71.0, "change": 3.1},
{"key": "fear_gauge", "label": "Risk Appetite", "value": 58.4, "change": null},
{"key": "social_momentum", "label": "Social Momentum", "value": 62.1, "change": -0.5},
{"key": "spy_trend", "label": "S&P 500 Trend", "value": 68.9, "change": 2.0},
{"key": "options_flow", "label": "Options Flow", "value": 57.3, "change": 1.4}
],
"history": [
{"date": "2026-04-01", "timestamp": 1743465600000, "score": 65.2,
"socialSentiment": 56.1, "marketDirection": 72.0, "fearGauge": 61.0,
"socialMomentum": 63.5, "spyTrend": 70.0, "optionsFlow": 59.8}
]
},
"sectors": {
"Information Technology": {"currentScore": 71.2, "phase": "Greed", "weeklyChange": 1.5},
"Health Care": {"currentScore": 48.3, "phase": "Neutral", "weeklyChange": -3.1}
}
}
Phase interpretation ( market.phase and each sector's phase, by score). Scores are fractional and each band includes its upper edge: Extreme Fear up to 15, Fear above 15 through 30, Anxiety above 30 through 45, Neutral above 45 through 55, Optimism above 55 through 70, Greed above 70 through 85, Extreme Greed above 85. So 55.16 reads Optimism. phase is "---" when the score is null.
sectors is keyed by the 11 GICS sector names ( Information Technology, Health Care, Communication Services, ...).
signals[] only lists signals present in the latest reading, so key off key, not array position or length. The history[] columns spell the same signals in camelCase: signals[].key fear_gauge is the fearGauge column, spy_trend is spyTrend, and so on, so convert snake_case to camelCase when you join a signal to its history.
Node SDK:
javascript
import SentiSense from 'sentisense';
const client = new SentiSense({ apiKey: process.env.SENTISENSE_API_KEY });
const mood = await client.marketMood.get();
console.log(mood.market.currentScore, mood.market.phase);
/api/v1/documents)#Note: Document responses include a
urlfield but no headline or title text. The API provides derived analytics (sentiment, entities, reliability), not source content. ThesourceNamefield identifies the publisher when it is known; it is oftennullon NEWS documents, so render a null as "publisher not named" rather than dropping the row. If your application needs to display titles, theurlfield links to the original source. Any content retrieval from source URLs is your application's independent action, subject to the source platform's terms. See our API Terms of Service.
News and social posts for a stock with sentiment scores. Public.
ParamTypeRequiredDefaultDescriptionsourcestringNoallNEWS, REDDIT, X, SUBSTACK, YOUTUBE``daysintNo7Lookback in days (1-365)hoursintNo-Lookback in hours, 1-8760 (overrides days). Out-of-range values return 400``limitintNo200Max results (capped at 200)
Response: { documents: [...], totalCount, searchTicker, source, startDate, endDate }. Each document includes: id, url, source, sourceName, published, averageSentiment, reliability, sentiment[]. Per-entity sentiment classifies each mentioned entity as POSITIVE/NEGATIVE/NEUTRAL.
Documents within a date range. Public.
ParamTypeRequiredDescriptionstartDateISO dateYese.g., 2025-01-01``endDateISO dateYese.g., 2025-01-31``sourcestringNoFilter by sourcelimitintNoMax results (capped at 200)
Documents mentioning an ontology entity. Public. Address it by urlSlug, e.g. Tim-Cook, the same handle the Metrics API takes. Internal KB ids are not accepted.
Smart search with natural language queries. Public.
ParamTypeRequiredDefaultDescriptionquerystringYes-e.g., AAPL earnings, Elon Musk TSLA``sourcestringNoallFilter by sourcedaysintNo7Lookback in days, 1 to 14. Larger values are capped at 14.limitintNo200Max results (capped at 500)
Latest documents from a specific source. Public. A short most-recent feed, not a windowed archive.
ParamTypeRequiredDescriptionsourcepathYesNEWS, REDDIT, X, SUBSTACK, YOUTUBE``daysintNoOldest document allowed, in days (default 7). It caps age; it does not make the feed reach back that farlimitintNoMost documents to return (default 100, capped at 500)sortstringNolatest (default, newest first) or top (reliability-first: recent documents are grouped into freshness buckets and ranked by publisher reliability within each bucket, so high-authority publishers surface first). Any other value returns 400.
A most-recent feed: on busy sources it covers hours rather than days. The feed returns up to limit of the most recent documents in the window, in the order sort asks for, counting only documents that carry an article body (items with a headline but no body are left out). Near-duplicate headlines are then collapsed, and on X and YouTube some low-authority posts are filtered out, so a response can come back under limit, at times well under; count the rows you received rather than assuming limit. totalCount equals the rows returned, not the size of the window, and there is no offset, so you cannot page further back. For a window that has to be complete, query /documents/ticker/{ticker} (with days or hours) or /documents/search instead.
AI-curated news story clusters. Public.
ParamTypeRequiredDefaultDescriptionlimitintNo20Max stories (capped at 50)filterHoursintNononeLookback window in hours, e.g. 720 for 30 days. This is the real lookback control for this endpoint. The window counts from when a story STARTED breaking, not from its latest article, so a running story with fresh coverage but an older start falls out of short windows (an empty short window can be correct). Setting it also switches ordering to curation score instead of the day-bucketed default.daysintNo7Accepted but has no effect on the response; ignored server-side. Use filterHours instead.offsetintNo0Pagination offsettickerstringNononeFilters the feed to clusters tagged with that stock, e.g. NVDA. With a ticker set, limit caps at 20 instead of 50, while filterHours and offset still apply, and a ticker we do not track returns an empty list. The path form /documents/stories/ticker/{ticker} is still available.
Response: Story objects with a top-level id AND clusterId (both equal to the cluster id -- pass either to /documents/stories/{clusterId}), plus cluster.title, cluster.averageSentiment, tickers, displayTickers, impactScore (0-10), brokeAt (epoch seconds, nullable), cluster.clusteredAt (epoch seconds). Each entry also carries cluster.storySource ( ORIGINAL for an editorially authored SentiSense Original, AI for a pipeline-generated story, always one of the two) and cluster.isLive (true while we are actively updating a developing story). Use tickers (bare symbols, e.g. ["AAPL"]) programmatically; displayTickers are human-formatted labels (e.g. ["Apple Inc (AAPL)"]) for display only, do not parse symbols out of them. The cluster.createdAt field (epoch millis) is deprecated and slated for removal; use cluster.clusteredAt.
Search the curated stories by a free-text query (Required). Public. Parsed like /documents/search: explicit kb/... ids, then entities recognised in the text (tickers, company names, people, organizations, products, topics), then the leftover words as keywords that must all appear in the story's own title or summary. Entity-scoped first, keyword-only retry when the recognised entities match nothing. days is the lookback (1 to 30, default 7; stories archive at 30 days), limit defaults to 20 and caps at 50. Newest first. Response: the same Story objects as /documents/stories; pass an id to /documents/stories/{clusterId} for the narrative. This is the endpoint for "what was the news flow on X about Y last month"; the unfiltered feed cannot answer it.
News stories for a specific stock. Public. Takes limit only (default 5, capped at 20): there is no lookback window here, so days / hours / filterHours are ignored. Use /documents/stories with filterHours for a freshness window.
Full detail for a single story cluster. Public -- Free: 20 story views/month, PRO: unlimited. Each list item from /stories and /stories/ticker/{ticker} carries a top-level id AND a clusterId (both equal to the cluster id); pass either one here as {clusterId}.
ParamTypeRequiredDescriptionclusterIdpathYesStory cluster ID (from /stories or /stories/ticker/{ticker})
Response: a flat story object (no {isPreview, data} wrapper) containing SentiSense-generated content and derived data only: id, createdAt, lastUpdatedAt; AI-written content ( title, summarizedContent, narrativeBody, bullishView, bearishView, aspectPerspectives; a side with no case in the sources is empty, never null: "" at the top level, {"hook": "", "risksOrCatalysts": [], "conclusion": "", "confidence": 0.0} inside aspectPerspectives[]); citationLinks (map of docN markdown references in narrativeBody to public article URLs); computed metrics ( averageSentiment, momentumScore, aiConfidence); source metadata ( clusterSize, sourcesList, primaryCategory, dominantEventType, publishersList, primaryPublisher, topPublishers); tickers, displayTickers, primaryEntityNames, relatedEntities; archived, totalDocuments; and provenance: storySource ( ORIGINAL for an editorially authored SentiSense Original, AI for a pipeline-generated story, always one of the two), isLive (true while we are actively updating a developing story), and timeline (dated updates newest first, each {publishedAt, updateType, content} where publishedAt is epoch millis, updateType is INITIAL / UPDATE / CORRECTION, and content is SentiSense-written markdown whose [docN] references resolve through citationLinks; empty array when the story has no updates).
Consistent with the documents policy above, publisher headlines, article text, and images are never included: the title and narrative are AI-generated by SentiSense, and citationLinks point to the original sources. Originals may embed SentiSense-authored chart images as standard markdown image links (  on sentisense.ai hosts) inside narrativeBody and timeline content; the fields stay markdown strings.
/api/v1/institutional)#Data from SEC 13F-HR filings. Filer categories: INDEX_FUND, HEDGE_FUND, ACTIVIST, PENSION, BANK, INSURANCE, MUTUAL_FUND, SOVEREIGN_WEALTH, ENDOWMENT, CONGLOMERATE, OTHER.
Important: /flows no longer requires reportDate: omit it to get the latest available quarter (the response is labeled with isPending + filer coverage), or pass one explicitly for a specific quarter. The other institutional endpoints (except /quarters) still require a reportDate. When you need one, call GET /quarters first to get valid dates; do not hardcode them. For a fully-filed quarter, use the reportDate from the first quarter with pending:false (the most-recent quarter is pending:true while inside the 45-day 13F filing window and holds only early filers; see /quarters below).
Available 13F reporting quarters. Public. Call this first.
Response: array of { value, label, reportDate, pending } objects sorted newest-first. pending is a boolean. Use the reportDate of the first quarter with pending:false; the most-recent quarter is pending:true while inside the 45-day 13F filing window and holds only early filers. Pass that reportDate (e.g., "2025-12-31") when calling other institutional endpoints.
Aggregate institutional buying/selling per ticker. Public (preview) -- Free: top 5, PRO: full data.
ParamTypeRequiredDescriptionreportDateISO dateNoQuarter to fetch (e.g., 2025-12-31). Omit to get the latest available quarter, including a still-open one; the response labels it with isPending + filer coverage. Pass a reportDate from /quarters for a specific quarter.limitintNoMax results per direction (default: 50, max: 100)
Response: { isPreview, previewReason, data: { inflows: [...], outflows: [...], reportDate, isPending, filerCount, baselineFilerCount } }. reportDate is the quarter served (useful when you omitted the param). isPending is true when that quarter is still inside the 45-day 13F filing window, so only early filers are represented; when pending, filerCount and baselineFilerCount give the coverage (e.g., 578 of 8789 filers) and are null otherwise. Each flow includes net share changes, new/closed positions, and per-category breakdowns (indexFundNetChange, hedgeFundNetChange, etc.). Flows are ranked by dollarFlowUsd (= netSharesChange × avgClosePrice): inflows DESC, outflows ASC. avgClosePrice is null and dollarFlowUsd is 0 for tickers without a cached quarterly price; clients should fall back to netSharesChange for those rows.
Institutional holders for a stock. Public (preview) -- Free: top 5, PRO: full data.
ParamTypeRequiredDescriptionreportDateISO dateNoQuarter end date. Omit it and the endpoint resolves the latest quarter that actually has holders for this ticker, preferring a settled quarter over a still-filing one, and echoes the quarter it used in data.reportDate.limitintNoPage size (1-1000). When present, returns a sorted page plus returnedCount/ offset and a notableChanges summary; when omitted, returns the full list (legacy). Mega-caps have 5,000+ holders, so paging is recommended.offsetintNoPage start within the sorted list (default 0; used with limit)sortBystringNoshares (default), valueUsd, or sharesChangePct (used with limit)sortDirstringNodesc (default) or asc (used with limit)
Response: { isPreview, previewReason, data: { ticker, companyName, reportDate, totalInstitutionalShares, holderCount, holders: [...] } }. The holder list is nested at data.holders (not data directly). Each holder includes filer name, category, shares, value, change type (NEW/INCREASED/DECREASED/SOLD_OUT/UNCHANGED). holderCount is always the full-quarter count; on paged requests data also carries returnedCount, offset, and notableChanges ( {count, top}: holders with a 10%+ change on 10k+ shares, top 5 by dollar impact). Free-tier previews return the top 5 rows and omit returnedCount, offset, and notableChanges even when limit is passed.
Activist investor positions (NEW or INCREASED stakes). Public (preview) -- Free: top 3, PRO: full data.
ParamTypeRequiredDescriptionreportDateISO dateYesQuarter end date
Convertible bond flows grouped by base ticker. Public (preview) -- Free: top 3, PRO: full data.
ParamTypeRequiredDescriptionreportDateISO dateYesQuarter end date
Institutional options activity with call/put breakdown. Public (preview) -- Free: top 3, PRO: full data.
ParamTypeRequiredDescriptionreportDateISO dateYesQuarter end date
Discover the universe of institutions: paginated, AUM-ranked list of filers (slug + metadata) so you can find what to query without knowing slugs upfront. Each institution is rolled up by parent filer, so a multi-filer manager (e.g. Vanguard) appears once with combined AUM. Summary only; use /institution/{slugOrCik} for full holdings. API key required, quota-exempt (per-minute rate limits still apply); full list for every key holder.
ParamTypeRequiredDescriptioncategorystringNoFiler category: INDEX_FUND, HEDGE_FUND, ACTIVIST, PENSION, BANK, INSURANCE, MUTUAL_FUND, SOVEREIGN_WEALTH, ENDOWMENT, CONGLOMERATE, OTHER``minAumUsdlongNoMinimum total AUM in USD (e.g. 10000000000)limitintNoPage size (default: 50, max: 200)offsetintNoPagination offset (default: 0)sortstringNoaumDesc (default), aumAsc, or nameAsc. Deterministic ordering, so pagination is stable.quarterstringNoAUM snapshot quarter as YYYYQN (e.g. 2026Q1); defaults to latest.
Response: { isPreview, previewReason, data: { quarter, totalCount, offset, limit, institutions: [...] } }. isPreview is always false here. Each institution: cik, urlSlug, displayName, filerCategory, totalValueUsd, holdingsCount, multiCikRollup, childCikCount. Bad inputs (unknown category/sort, negative offset/minAumUsd, quarter with no data) return 400.
Full profile, summary stats, and current-quarter equity holdings for a specific institutional filer. Resolved by URL slug (e.g. Berkshire-Hathaway) or by the 10-digit zero-padded CIK (e.g. 0001067983, the form filerCik is returned in). An unpadded CIK such as 1067983 returns 404, so pad it to 10 digits first. PRO (preview) -- Free: profile + top 10 holdings, PRO: full holdings array. Returns 404 if the slug or CIK is unknown.
Response: { isPreview, previewReason, data: { filerCik, displayName, urlSlug, filerCategory, totalValueUsd, holdingsCount, latestReportDate, quartersTracked, newPositions, increasedPositions, decreasedPositions, soldOutPositions, multiCikRollup, childCikCount, childCiks, holdings: [...] } }. multiCikRollup/ childCikCount/ childCiks describe parent/subsidiary rollups (e.g. Vanguard) and are present for all tiers ( childCiks is null when not a rollup). Holding objects include ticker, companyName, shares, valueUsd, changeType, sharesChange, sharesChangePct, portfolioWeight.
/api/v1/insider)#SEC Form 4 insider trading data: track buys, sells, awards, and exercises by company officers, directors, and 10%+ shareholders. Updated daily. Includes cluster buy detection (a historically bullish signal).
Insider relationships: OFFICER, DIRECTOR, TEN_PCT_OWNER, OTHER. Each filer also has independent officer, director, tenPctOwner booleans (a person can be both officer and director).
Transaction types: BUY, SELL, EXERCISE, AWARD, GIFT, OTHER. To count open-market activity, filter transactionType to BUY or SELL; AWARD (grants), GIFT, and EXERCISE are not open-market trades and should be excluded from a buys/sells tally. The transactionType filter alone misses one case: rows with raw transactionCode F (shares withheld to cover taxes on vesting) arrive typed SELL, so drop code-F rows from sell tallies too; on names with heavy stock compensation they can be most of the reported selling. This applies when you tally rows yourself from /insider/trades/{ticker}, which returns every filed row untouched. The server-side rollup at /insider/activity already excludes code F from its sells, so do not subtract it a second time there. Sanity-check totalValue against sharesTransacted times pricePerShare before headlining a dollar figure. Note the insider endpoint uses BUY/ SELL, NOT the politician endpoint's PURCHASE/ SALE vocabulary (a filter written for one returns zero on the other).
Market-wide insider buying and selling aggregated by ticker: a leaderboard of the largest by dollar value, not every ticker with activity. Public (preview) -- Free: top 5 per side, PRO: top 50 per side.
ParamTypeRequiredDefaultDescriptionlookbackDaysintNo90Days to look back (1-365)
Response (FREE tier): { isPreview: true, previewReason: "PRO_REQUIRED", totalCount, data: { buys: [...], sells: [...] } }. PRO: { isPreview: false, previewReason: null, data: { buys: [...], sells: [...] } }. Each entry: ticker, companyName, tradeCount, insiderCount, totalShares, totalValue, latestDate, latestInsider, latestTitle.
Each list is capped at 50 tickers, ranked by totalValue descending, on every tier. There is no limit or offset, and the PRO response carries no totalCount, so a full list of 50 means "the 50 largest", never "all 50 there were". A longer lookbackDays pushes smaller names out: a ticker that shows up in the 30-day list can be missing from the 90-day one. The FREE totalCount is the buys plus sells of those capped lists (at most 100), not a count of tickers with activity. For "how many stocks had insider buying" or "did insiders buy X", read /insider/trades/{ticker} per name rather than this rollup. latestInsider and latestTitle are each picked from the window's rows independently, so they name an insider who traded in the window, not necessarily the most recent filer, and the two can come from different filings; read /insider/trades/{ticker} for who filed last.
Insider transactions for a specific stock, newest first. Public (preview) -- Free: top 5, PRO: full data.
ParamTypeRequiredDefaultDescriptiontickerpathYes-Stock ticker (e.g., AAPL)lookbackDaysintNo90Days to look back (1-365)
Response: { isPreview: bool, previewReason: string|null, data: [...] }. Free: top 5 trades, PRO: full list. Each trade: ticker, companyName, insiderName, insiderTitle, insiderRelation, officer, director, tenPctOwner, transactionDate, filedDate, transactionCode, transactionType, securityTitle, sharesTransacted, pricePerShare, totalValue, sharesOwnedAfter, directOwnership, rule10b51.
python
client = SentiSenseClient(api_key=os.environ["SENTISENSE_API_KEY"])
trades = client.get_insider_trades("AAPL", lookback_days=90)
for t in trades.data:
print(f"{t['transactionDate']} {t['insiderName']} {t['transactionType']} {t['sharesTransacted']} shares")
Cluster buy signals: stocks where 3+ distinct insiders purchased recently. Public (preview) -- Free: top 5, PRO: top 50.
ParamTypeRequiredDefaultDescriptionlookbackDaysintNo90Days to look back (1-365)
Response: { isPreview: bool, previewReason: string|null, totalCount?, data: [...] }. Free: top 5 signals with totalCount, PRO: up to 50. Each entry: { ticker, companyName, insiderCount, tradeCount, totalShares, totalValue, firstBuyDate, lastBuyDate }. Ranked by insiderCount descending, then totalValue, and capped at 50 on every tier with no limit or offset: on a long window (365 days) the list fills to 50 and drops three-insider clusters a shorter window shows. Treat exactly 50 rows as "the 50 broadest clusters", not the complete set; the FREE totalCount counts that capped list.
/api/v1/politicians)#Congressional STOCK Act trading disclosures: purchases, sales, and exercises by U.S. Senators and Representatives. Updated daily from official filings.
Chambers: SENATE, HOUSE.
Transaction types: PURCHASE, SALE, EXCHANGE, OTHER.
Amount ranges: STOCK Act disclosures report dollar amounts as ranges (e.g., "$1,001 - $15,000"), not exact values. The API returns the raw range string plus parsed amountMin/ amountMax.
Recent congressional trades across all politicians, paged, sorted by disclosure date (most recently disclosed first) and tie-broken to a total order so limit/ offset page without dropping or repeating rows. "Recent" means recently disclosed, not recently traded: a filing can reveal a transaction made up to 45 days earlier. Public (preview) -- Free: top 5, PRO: pages the whole window.
ParamTypeRequiredDefaultDescriptionlookbackDaysintNo90Trailing window applied to the disclosure date (1-365)limitintNo200Rows per page. Above 500 is clamped, not rejected. Returns 400 invalid_limit below 1offsetintNo0Rows to skip, for paging
Response: { isPreview, previewReason, totalCount, data: [...] }. totalCount is the size of the whole window, not the page, so offset + data.length < totalCount means there is another page. Each trade: politicianName, firstName, lastName, chamber, party, state, bioguideId, imageUrl, ticker, assetDescription, assetType ( Stock, ETF, or Stock Option), assetMetadata (object: null, or {kind:"OPTION", optionType, strikePrice, expirationDate} when option terms were parsed from the filing, which is uncommon; identify option rows by assetType == "Stock Option", not by this field), transactionType, transactionDate, disclosureDate, disclosureDelayDays, amountRange, amountMin, amountMax, owner, urlSlug, sentiSenseScore. That last field is reserved: it is present on every row and currently null on all of them, so read the ticker's Score from /stocks/{ticker}/sentiment rather than building on it here.
python
client = SentiSenseClient(api_key=os.environ["SENTISENSE_API_KEY"])
activity = client.get_politician_activity(lookback_days=90)
for trade in activity.data:
print(f"{trade['politicianName']} ({trade['party']}-{trade['state']}): {trade['transactionType']} {trade['ticker']}")
Congressional trades for a specific stock, sorted by disclosure date (most recently disclosed first). Public (preview) -- Free: top 3, PRO: full data.
ParamTypeRequiredDefaultDescriptiontickerpathYes-Stock ticker (e.g., NVDA)lookbackDaysintNo90Trailing window applied to the disclosure date (1-365)
Response: same preview wrapper and trade object schema as /activity.
All tracked politicians with trading summaries, sorted by total trade count. Public (preview) -- Free: top 5, PRO: full list.
No parameters.
Response: { isPreview, previewReason, data: [...] }. Each entry: urlSlug, displayName, firstName, lastName, chamber, party, state, bioguideId, imageUrl, totalTrades, purchaseCount, saleCount, latestTradeDate.
Every tracked member of Congress and the slug that identifies them, so you can find who is worth querying without knowing slugs upfront. Summary only, no trade data. API key required, not tier-gated (FREE and PRO get the same full response), and it does not count against your monthly quota.
Unlike /members, which lists who currently holds office, the directory lists everyone we track, including members who have left Congress. Those carry former: true and servedUntil.
ParamTypeRequiredDefaultDescriptionqstringNo-Case-insensitive filter across display name, state and slug (max 100 chars)limitintNo50Results per page (max 200)offsetintNo0Results to skip, for paging
Response: { isPreview, previewReason, data: { members: [...], totalCount } }. Each member: urlSlug, displayName, chamber, party, state, bioguideId, imageUrl, former, servedUntil. Read totalCount to page: limit caps at 200, so a larger value is silently clamped rather than rejected.
Use this to resolve a name to a slug, then call /politicians/member/{slug} for that member's filings.
Detailed profile for a single politician: summary stats, recent trades, and top tickers. Public (preview) -- Free: preview-wrapped, PRO: full detail.
ParamTypeRequiredDefaultDescriptionslugpathYes-Politician URL slug (from /members)limitintNo200Trades per page in recentTrades. Above 500 is clamped to 500; below 1 returns 400 invalid_limit``offsetintNo0Trades to skip, for paging the history. Negative returns 400 invalid_offset
Response: { isPreview, previewReason, totalCount, data: { profile: {...}, recentTrades: [...], topTickers: [...] } }.
recentTrades is one page of the member's history, newest transaction first, not all of it. Most members disclose a few dozen trades and arrive complete in the default page; a handful have disclosed thousands. totalCount is the whole history, so offset + recentTrades.length < totalCount means there is another page. profile and topTickers always describe the whole history whatever page you ask for, so profile.totalTrades does not shrink with a small limit.
/api/v1/insights)#AI-generated signals for stocks and the overall market. Each insight identifies a specific pattern: insider cluster buying, institutional position changes, volume anomalies, sentiment baseline deviations, and more. Most lists are sorted by urgency then confidence; the per-stock endpoint ( /stock/{ticker}) is ranked by importance (relevance, confidence, and recency) so fresh signals lead.
Insight fields: insightId, insightType, ticker (the stock the insight is about, or "MARKET" on market-wide insights such as market_insider_trend), category ( SENTIMENT/ TRENDING/ TECHNICAL/ FUNDAMENTAL/ PERSONALIZED, or null), insightText, confidence (0.0-1.0)