Stocks API
Stock prices delayed 15 minutes, historical charts, company fundamentals, short interest data, and AI-powered stock analysis.
Overview
The Stocks API provides comprehensive stock data including 15-minute-delayed prices, historical charts, company fundamentals, short interest metrics, and AI-powered analysis reports. Every endpoint requires an API key (free to generate in Settings > Developer Console); most are available in full on the Free tier.
Stock Lists & Metadata
GET /
Returns all available stock ticker symbols tracked by SentiSense.
Authentication: API key required | Parameters: None
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks"
Response: string[] (e.g., ["AAPL", "MSFT", "GOOGL", ...])
GET /detailed
Returns all stocks with company name, KB entity ID, and URL slug.
Authentication: API key required | Parameters: None
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/detailed"
Response object:
| Field | Type | Description |
|---|---|---|
ticker |
string | Ticker symbol |
name |
string | Company name |
kbEntityId |
string | Ontology entity ID |
urlSlug |
string | URL-friendly slug |
socialDominance |
object | null | Precomputed share of voice. value is share as a 0-1 decimal, rank is 1-based across the coverage universe, percentile is 0-100. Null when no signal exists. Refreshed daily. |
GET /popular
Returns popular stock tickers. Parameters: None
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/popular"
Response: string[]
GET /popular/detailed
Returns popular stocks with company details. Same schema as /detailed.
GET /images
Returns company logo/icon URLs for a batch of tickers.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
tickers |
string | Yes | - | Comma-separated tickers (max 600) |
forced |
boolean | No | false | Bypass cache |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/images?tickers=AAPL,TSLA,NVDA"
Response: Map<ticker, { iconUrl, logoUrl }>: URLs for company icons and logos. GET a URL directly to receive the image bytes; no API key is required for the image fetch itself, so the URLs can be used straight in an <img src> tag.
Treat these URLs as refreshable rather than permanent. Brand assets are periodically refreshed, and a URL issued for a previous revision stops resolving once that happens. Re-read them from this endpoint instead of storing them long term.
GET /descriptions
Returns company profiles with branding, market cap, and sector information.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
tickers |
string | Yes | - | Comma-separated tickers |
forced |
boolean | No | false | Bypass cache |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/descriptions?tickers=AAPL,MSFT"
Per-Stock Data
GET /{ticker}/similar
Returns peer and similar stocks based on sector, industry, and SentiSense ontology relationships.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
path | Yes | - | Stock ticker symbol |
limit |
integer | No | 5 | Max results |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/similar?limit=10"
GET /{ticker}/profile
Returns a company profile including CEO, sector, industry, and market data.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
path | Yes | - | Stock ticker symbol |
forced |
boolean | No | false | Bypass cache |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/profile"
Listing status: the profile also carries listingStatus, delistedDate and delistingReason when the symbol is delisted or pending delisting. All three are absent for a normally listed symbol, and they carry the same values as on GET /price: listingStatus is "DELISTED" or "PENDING_DELISTING", delistedDate is the ISO date trading stopped, and delistingReason is one of acquired, take_private, bankruptcy, exchange_rule, merged.
ETF profiles: when ticker identifies a tracked ETF, the response 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 is the same value returned by the /etfs endpoints. It is square like logoUrl and iconUrl and drops into the same avatar slot, but it is a first-party asset rather than a vendor branding mark, so it is returned as a direct URL. It is absent for issuers we hold no image for.
GET /{ticker}/entities
Returns SentiSense ontology entities related to a stock (e.g., CEO, key products, partner companies).
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/entities"
Response: array of related entities. Each entry:
| Field | Type | Description |
|---|---|---|
id |
string | Deprecated: not a stable public identifier. Use urlSlug to refer to an entity. |
displayName |
string | Entity display name |
type |
string | PERSON, PRODUCT, ORGANIZATION, etc. |
relatedStock |
string | The ticker you queried |
urlSlug |
string|null | Handle for the Metrics API {entityId} parameter (e.g. Tim-Cook) |
title |
string|null | Person's role (e.g. CEO) |
category |
string|null | Product category |
appId |
string|null | Apple App Store id when the product has a tracked companion app |
GET /{ticker}/graph
Returns the typed relationships around one stock, including leaders, products and product families, peers, owners and subsidiaries, publishers, and topics.
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/graph?depth=1&cap=75"
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
depth |
integer | No | 1 | Traversal depth, either 1 or 2 |
cap |
integer | No | 75 | Maximum non-root nodes, from 1 to 200 |
Response: a bounded graph projection with the requested stock as its root.
| Field | Type | Description |
|---|---|---|
ticker |
string | Uppercase ticker symbol |
root |
string | Slug of the root company; matches one entry in nodes |
depth |
integer | Applied traversal depth |
cap |
integer | Applied non-root node cap |
truncated |
boolean | true when more matching nodes exist beyond cap |
omitted |
integer | Nodes left out because they carry no slug, and so cannot be addressed |
counts |
object | Returned nodes, edges, and node totals in byType |
groups |
object | Slugs grouped as people, products, productFamilies, peers, organizations, publishers, and topics |
nodes[] |
array | Nodes with slug, displayName, and type; PRODUCT_OR_SERVICE nodes also carry a string category when non-null, matching the product category on /{ticker}/entities |
edges[] |
array | Relationships with source, target, type, direction, and properties |
{
"ticker": "AAPL",
"root": "Apple-Inc",
"depth": 1,
"cap": 75,
"truncated": false,
"omitted": 0,
"counts": {
"nodes": 3,
"edges": 2,
"byType": { "COMPANY": 1, "PERSON": 1, "PRODUCT_OR_SERVICE": 1 }
},
"groups": {
"people": ["Tim-Cook"],
"products": ["iPhone"],
"productFamilies": [],
"peers": [],
"organizations": [],
"publishers": [],
"topics": []
},
"nodes": [
{ "slug": "Apple-Inc", "displayName": "Apple Inc.", "type": "COMPANY" },
{ "slug": "Tim-Cook", "displayName": "Tim Cook", "type": "PERSON" },
{ "slug": "iPhone", "displayName": "iPhone", "type": "PRODUCT_OR_SERVICE", "category": "Smartphones" }
],
"edges": [
{ "source": "Tim-Cook", "target": "Apple-Inc", "type": "LEADS", "direction": "DIRECTED", "properties": {} },
{ "source": "iPhone", "target": "Apple-Inc", "type": "PRODUCT_OF", "direction": "DIRECTED", "properties": { "sourceProperty": "associatedCompany" } }
]
}
Handles: slugs are the only identifier here. The same string does three jobs: it joins groups and edges to nodes inside one response, it addresses the entity on the Metrics API and Documents API, and it is the entity page path (/entities/Tim-Cook). A product family is { "family": "iPhone", "members": ["iPhone-15"] }, slugs on both sides.
Edge types: OWNS, PEER, BELONGS_TO, LEADS, FOUNDED, AFFILIATED_WITH, VARIANT_OF, SUBTOPIC_OF, and SUBSIDIARY_OF are curated relationships. PRODUCT_OF is derived from a product's associated company.
Direction: DIRECTED preserves the relationship from source to target. BIDIRECTIONAL combines matching relationships present in both directions.
Edge properties: properties maps string keys to string values and is {} when the relationship carries no detail. Keys include role (the person's title on a LEADS edge, e.g. "Chief Executive Officer"), since (the year a LEADS relationship began, e.g. "2011"), and year (the founding year on a FOUNDED edge). Other keys may appear, so treat the map as open.
Unknown ticker: returns 404 with error: "entity_not_found" and up to three suggestions from entity search, plus reason: "non_us_listing" when the symbol is a non-US listing.
Free with an API key; rate limits apply. One ticker per call; there is no enumeration endpoint.
GET /{ticker}/ai-summary
Returns an AI-generated stock analysis report. PRO feature with limited Free access: depth=basic returns a preheader summary (Free: unlimited). depth=deep returns a full multi-section report (Free: 10 views/month, PRO: unlimited). Returns 429 with {error: "quota_exceeded", message, ...} when Free quota is exhausted, matching the platform-wide quota contract. message says when the allowance resets (the start of next month) and links PRO, which has no monthly report limit. The response has no Retry-After header.
Authentication: API key required
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
path | Yes | - | Stock ticker symbol |
depth |
string | No | basic |
Analysis depth: basic or deep |
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/ai-summary?depth=deep"
Response Schema: flat object (no {isPreview, data} wrapper).
| Field | Type | Description |
|---|---|---|
ticker |
string | Ticker symbol |
companyName |
string | Company name |
status |
string | READY, DRAFT, NOT_AVAILABLE, or ERROR. Only READY carries report content; treat any other value as no report. Without content, sections, sectionOrder, moatRating and aiDisruptionRisk are omitted from the response, and companyName and version can be omitted too |
statusReason |
string | null | Present on every status other than READY |
reportType |
string | SUMMARY for depth=basic, FULL for depth=deep |
version |
integer | Report date encoded as yymmdd (e.g. 260520) |
lastUpdated |
long | Epoch milliseconds |
sections |
object | Map of section name to {content, directives}. Present on both depths when status is READY. depth=basic returns a single Executive Summary section; depth=deep returns the full set. |
sectionOrder |
string[] | Ordered section keys for rendering. Present on both depths when status is READY. ["Executive Summary"] on depth=basic. |
moatRating |
integer | null | Proprietary moat quality score 0 to 10. Present on depth=deep only. null if not yet assessed for this ticker. |
aiDisruptionRisk |
string | null | Low, Medium, High, or Critical: AI revenue-displacement exposure. Present on depth=deep only. null if not yet assessed. |
Check status == "READY" before reading any section. Do not branch on the presence of sections to decide whether you received a deep report: both depths return it. Read reportType (SUMMARY vs FULL), or check the length of sectionOrder.
GET /{ticker}/metrics/{metricType}/breakdown
Returns sentiment or mention metrics broken down by entity for a stock over a time range.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
path | Yes | - | Stock ticker |
metricType |
path | Yes | - | Metric type (e.g., sentiment, mentions) |
startTime |
long | Yes | - | Start time (epoch ms) |
endTime |
long | Yes | - | End time (epoch ms) |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/metrics/sentiment/breakdown?startTime=1745600000000&endTime=1746204800000"
Market Data & Prices
GET /price
Returns the latest price for a single stock ticker, delayed 15 minutes.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
string | Yes | - | Stock ticker symbol |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/price?ticker=AAPL"
Response:
| Field | Type | Description |
|---|---|---|
ticker |
string | Ticker symbol |
currentPrice |
double | Regular-session price, delayed 15 minutes. During RTH (09:30 to 16:00 ET): the most recent regular-session value. Otherwise: most recent regular-session close. |
change |
double | currentPrice change vs previousClose |
changePercent |
double | currentPrice change percentage |
previousClose |
double | Previous closing price |
volume |
long | Volume |
timestamp |
long | When this response was served (epoch milliseconds). Not the age of the price: it tracks the current clock regardless of how old the value is. |
priceAsOf |
long | absent | When the market data behind currentPrice is from (epoch milliseconds). This is the field to read for freshness. Omitted outside regular hours, and whenever the upstream data is not dated, so treat its absence as "unknown" rather than "fresh". |
extendedHours |
object | null | Extended-hours view (pre-market or after-hours). Absent during RTH, overnight, and weekends. See below. |
listingStatus |
string | absent | "DELISTED" or "PENDING_DELISTING". Present only when the symbol is delisted or pending delisting, absent otherwise. |
delistedDate |
string | absent | ISO date (YYYY-MM-DD) trading stopped. Present only alongside listingStatus: "DELISTED". |
delistingReason |
string | absent | One of acquired, take_private, bankruptcy, exchange_rule, merged. Present only alongside listingStatus: "DELISTED". |
Delisted symbols return their last trade price rather than an error, and listingStatus is what marks that price as frozen. On a "DELISTED" symbol, currentPrice, change and changePercent are the final trading session's values and never advance again. priceAsOf is the close of that final session (it can fall a day or more before delistedDate), extendedHours is absent, and timestamp is still the serve time. Read listingStatus before rendering a price as current.
extendedHours object:
| Field | Type | Description |
|---|---|---|
session |
string | "pre" (04:00 to 09:30 ET) or "post" (16:00 to 20:00 ET) |
price |
double | Live extended-hours price |
change |
double | Extended-hours price change vs currentPrice |
changePercent |
double | Extended-hours change percentage vs currentPrice |
GET /prices
Returns the latest prices for multiple tickers in a single request, delayed 15 minutes (see /price above).
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
tickers |
string | Yes | - | Comma-separated tickers |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/prices?tickers=AAPL,TSLA,NVDA"
Response: StockPrice[] (JSON array). Each element is the same price object as /price, including a ticker field identifying the symbol, an optional extendedHours object during pre/post sessions, and the optional listingStatus / delistedDate / delistingReason fields. Check each element for a frozen price rather than assuming a batch is uniformly live. Tickers that fail to resolve are silently omitted from the array.
GET /chart
Returns historical OHLCV (Open, High, Low, Close, Volume) chart data for a stock.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
string | Yes | - | Stock ticker symbol |
timeframe |
string | No | 1M |
Chart timeframe: 1D, 5D, 1W, 1M, 3M, 6M, 1Y, 5Y, 10Y, MAX |
Up to 26 years of split- and dividend-adjusted history. MAX returns a stock's full available
history, back to 1999 for names listed that long: 320 monthly bars for AAPL, versus the 5 years
most price APIs cap at. 10Y returns weekly bars over ten years.
Granularity is chosen per range so a long chart stays a sensible payload: 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 and 10Y, monthly for MAX.
Ranges of 10Y and MAX are adjusted for both splits and dividends, so a long series is
comparable end to end rather than showing a cliff at every corporate action. Shorter ranges,
including 5Y, are split-adjusted only. The two bases therefore differ on the same historical
date, by roughly the dividends paid since: negligible for a non-payer, around 14% over five years
for a 3% yielder. volume is restated to today's share count in every range, so a pre-split bar
reports shares on the current basis and the volume series has no cliff either. Only splits move
it: a dividend changes the price basis but not the number of shares that changed hands. Every
bar carries adjusted: true to mark that basis.
One consequence of the restatement surprises people, so it is worth stating plainly: on a stock
with a large cumulative split factor, an old bar can report a share count many times larger 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. Measured on the monthly series in September 2026, that puts a
2008 bar near 24 billion shares against roughly 1 billion for a recent month. That is the
restatement working, not a data error, and the series is continuous across every split.
202 Accepted on 10Y and MAX means that stock's deep history is still being assembled.
The body is an empty array and a Retry-After header gives the suggested wait in seconds; retry
and you will get the full series. We return this rather than silently substituting a shorter
range, so a 200 always means the range you asked for. It only happens on the first request for
a rarely-viewed stock.
A timeframe value outside the list above answers 400 Bad Request with an invalid_timeframe
error naming the valid values.
Response: array of bars. Each bar has:
| Field | Type | Description |
|---|---|---|
timestamp |
long | Unix timestamp in milliseconds |
date |
string | Pre-formatted display string (format varies by timeframe) |
open |
double | Opening price |
high |
double | Highest price during the bar |
low |
double | Lowest price during the bar |
close |
double | Closing price |
volume |
long | Bar volume, on the same restated basis as the prices (see adjusted) |
session |
string | null | US-equity session: pre (04:00 to 09:30 ET), regular (09:30 to 16:00 ET), or post (16:00 to 20:00 ET). Populated for intraday timeframes (1D, 5D, 1W, 1M); null for daily, weekly, and monthly bars (3M and longer) that span whole sessions. The 1M timeframe returns regular-session bars only. |
adjusted |
boolean | Always true: the bar is restated to the stock's current share count rather than served as it printed at the time. |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/chart?ticker=AAPL&timeframe=6M"
Migrating from an internal chart endpoint on another site? GET /chart is the documented
equivalent, with full OHLCV bars instead of close-only pairs. Field-by-field mapping:
the migration guide.
GET /market-status
Returns the current US market status: open while the regular trading session is open, closed otherwise. Pre-market and after-hours report as closed.
Parameters: None
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/market-status"
Response:
| Field | Type | Description |
|---|---|---|
status |
string | open or closed |
timestamp |
long | When the status was computed (epoch milliseconds) |
Fundamentals
Two endpoints share one period object. /fundamentals returns a single fiscal period, the
latest by default, plus trailing-twelve-month, price-ratio and market fields where available./fundamentals/history returns up to 40 quarters or 20 years of the same object with the
statement fields and derived ratios filled in and the rest null. /fundamentals/periods lists which periods exist, and/fundamentals/current is a compact price-and-TTM profile. The period object is documented once,
under GET /fundamentals/history.
Reporting currency. Statement figures are served as the filer reports them, in the filer's
own currency, and are never converted to US dollars. US filers report in USD; foreign filers
listed as ADRs report in their home currency (ASML in EUR, Toyota in JPY, SK hynix in KRW)./fundamentals,/fundamentals/currentand every/fundamentals/historyperiod carry an
optionalreportedCurrencyfield ("USD", "EUR", "KRW", ...) naming that currency. When the field
is absent, the currency is unknown, not implicitly USD.Do not mix these figures with the share price. The listed price is the USD ADR price, so when
reportedCurrencyis present and not USD the API servespeRatio,psRatioandpbRatioasnullrather than a cross-currency number. Margins, returns and liquidity ratios have the same currency on both
sides and are served for every filer.
GET /fundamentals
Returns one fiscal period. With no fiscalPeriod and fiscalYear, that is the most recent filed
period for the timeframe, enriched with live market data. With both, it is that period as filed,
without the market data (see the table below). Supplying only one of the two does not select a
period; you get the latest one.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
string | Yes | - | Stock ticker |
timeframe |
string | No | quarterly |
quarterly or annual |
fiscalPeriod |
string | No | - | Specific period (e.g. Q4 or FY). Only honoured together with fiscalYear. |
fiscalYear |
string | No | - | Specific fiscal year (e.g. 2024). Only honoured together with fiscalPeriod. |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals?ticker=AAPL&timeframe=quarterly"
Response: one period object, the shape documented under
GET /fundamentals/history, plus the fields that history leaves null:
| Field | On /fundamentals |
|---|---|
revenueTTM, netIncomeTTM, epsTTM |
The sum of the filed periods that end with this period and together cover twelve months: four rows for a quarterly filer, two for a filer that reports half-years. epsTTM is on the diluted basis where the provider reports one. Null on timeframe=annual, null for any line that one of those periods lacks, and null when the filed periods cannot be assembled into a twelve-month window. Across a stock split, epsTTM can be built from split-adjusted quarterly figures, so it will not always equal the sum of the history rows' epsDiluted. |
quartersIncluded |
The number of filed periods in the trailing-twelve-month window: 4 for a quarterly filer, 2 for a half-year filer. The trailing sums are filled only when this is present. Null on timeframe=annual, and null when no twelve-month window could be assembled. |
currentPrice |
A delayed USD price, cached here for up to 30 minutes; use the quote endpoints when you need the price itself. Latest-period requests only. |
marketCap |
USD market capitalisation from the company profile. Latest-period requests only, and null when the profile carries no market cap or the period was served from the statement source (see below). |
sharesOutstanding |
Deprecated. On a latest period that carries marketCap, it is an estimate marketCap / currentPrice rather than a reported count; see the note under /fundamentals/history. |
peRatio |
currentPrice / epsTTM; on timeframe=annual, currentPrice / epsDiluted for the year (or epsBasic when there is no diluted figure). Latest-period requests only, null for non-USD filers and when the EPS input is zero or negative. |
psRatio |
marketCap / revenueTTM; on timeframe=annual, price over the year's revenue per share. Null for non-USD filers and on responses without market data. |
pbRatio |
currentPrice over book value per share (totalEquity / sharesOutstanding). Null for non-USD filers, when equity is not positive, and on responses without market data. |
roe, roa |
netIncomeTTM / totalEquity and netIncomeTTM / totalAssets, in percent. On timeframe=annual, the year's netIncome is used instead. |
companyName |
Filled only on latest periods that carry market data. |
The latest period is served from one of two sources, chosen per ticker by which one has the
fresher filing, so a ticker can move between them. Responses from the market-data source carry
the full set above. Responses from the statement source carry the trailing sums, currentPrice
and peRatio but no marketCap, psRatio, pbRatio or companyName, and theirsharesOutstanding is the weighted-average form used on history rows. A null marketCap on a
latest period tells you which one you got.
GET /fundamentals/periods
Lists the fiscal periods available for a ticker, quarterly and annual together:{ ticker, periods: [{ fiscalPeriod, fiscalYear, filingDate, periodEndDate, timeframe }] }. Order
is not guaranteed; sort on periodEndDate yourself.
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/periods?ticker=AAPL"
GET /fundamentals/current
Returns a compact trailing profile, not a statement: ticker, currentPrice, epsTTM, revenueTTM,peTTM, psTTM, quartersIncluded, reportedCurrency, fetchedAt, plus available andreason. Use it when you only need trailing P/E and P/S; for statement lines use /fundamentals.
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/current?ticker=AAPL"
GET /fundamentals/history
Returns a multi-period history of full financial statements (income statement, balance sheet and
cash flow), one entry per statement period the provider publishes, plus any pre-IPO quarter
described under Reading the rows, newest first. This is the
endpoint behind the statement tables on the Financials tab: use it for margin trends, multi-year
comparisons, or as the input data for a valuation model. Not the same as /fundamentals (a single
period) or /fundamentals/historical/revenue (income-statement lines only, recent periods only).
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
string | Yes | - | Stock ticker |
timeframe |
string | No | quarterly |
quarterly or annual |
limit |
integer | No | 12 quarterly / 10 annual | Periods to return. Values above 40 quarterly / 20 annual are clamped to the cap. |
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/history?ticker=AAPL&timeframe=annual&limit=10"
Response: { ticker, timeframe, count, dataSource, reason, periods[] }. count is the number
of periods returned, below limit when the provider has fewer. Periods are sorted byperiodEndDate, newest first. A ticker with no statements (an unknown symbol, an ETF or fund, a
very recent listing) returns 200 with count: 0, an empty periods and a fixed explanatoryreason; it is not a 404. dataSource is deprecated and carries no information: "" on every
period and on a non-empty envelope, null on an empty one.
The period object
Every field below is present on every period, except reportedCurrency, which is omitted when
unknown. ticker, fetchedAt and dataSource are never null. Every other field is null when the value is unavailable for that period: the provider did
not publish the line, a consistency check rejected it, or a calculation lacked an input. Null is
never zero, and never a reason to fill in a neighbouring field; the one substitution we recommend
is spelled out in the sharesOutstanding note below. On /fundamentals/history the last group is
null on every row; those fields are filled only by /fundamentals.
Identity
| Field | Type | Description |
|---|---|---|
ticker |
string | The requested symbol. |
fiscalPeriod |
string | Q1 to Q4 on quarterly rows, FY on annual rows, on the filer's fiscal calendar (Apple's Q1 ends in December). |
fiscalYear |
string | The filer's own fiscal-year label. It can differ from the calendar year of periodEndDate: Lululemon's year ending 2025-02-02 is fiscal "2024". |
periodEndDate |
string | Last day of the period as an ISO date (2025-09-27). The field to sort and join on. |
periodMonths |
integer | Months the period covers: 3 for a quarter, 6 for a filer that reports half-years, 12 for a year. fiscalPeriod names the quarter a period ends in, so a half-year period is labelled Q2 or Q4; this field is what distinguishes the two. Null when the span cannot be established: the oldest row of a response, which has nothing behind it to measure against, and a row after a missing period whose own figures do not settle its length. |
filingDate |
string | Date the statement was filed, ISO date. |
companyName |
string | Null on history rows. |
Income statement (amounts in reportedCurrency)
| Field | Type | Description |
|---|---|---|
revenue |
number | Total revenue. |
costOfRevenue |
number | Cost of revenue. Served null, together with grossProfit and grossMargin, when the provider's line fails our consistency check: operating expenses folded into cost of revenue or the reverse, a cost of revenue below zero, or a cost of revenue larger than the period's total operating costs while its gross margin falls far below the neighbouring periods'. |
grossProfit |
number | Gross profit. |
operatingIncome |
number | Operating income. Null for a period in which the filer's own filings carry no operating-income line (common for banks, insurers and some industrial and pharmaceutical filers, which report income before taxes directly). When the filer's filings cannot be checked, the provider's figure is served. |
netIncome |
number | The provider's consolidated net income line. Not the EPS numerator. |
bottomLineNetIncome |
number | The provider's bottom-line income line, which can differ from netIncome in size and in sign; see the worked example below. Always null on rows from our fallback source. |
eps |
number | Compatibility field with a mixed basis: basic EPS, except on fallback-source history rows where it is the diluted figure when one exists. Prefer epsBasic or epsDiluted, which name their basis. |
epsBasic |
number | Basic earnings per share, as reported. |
epsDiluted |
number | Diluted earnings per share, as reported. Null when the provider reports no diluted figure. |
Share counts (a number of shares)
| Field | Type | Description |
|---|---|---|
weightedAverageSharesBasic |
integer | Basic weighted-average shares for the period. Null when the provider reports none. |
weightedAverageSharesDiluted |
integer | Diluted weighted-average shares for the period. Null when the provider reports none. |
sharesOutstanding |
integer | Deprecated, see the note below. On history rows it equals weightedAverageSharesDiluted, or the basic figure when there is no diluted one. Always null on rows from our fallback source. |
Balance sheet (amounts in reportedCurrency)
| Field | Type | Description |
|---|---|---|
totalAssets |
number | Total assets. |
totalLiabilities |
number | Total liabilities. |
totalEquity |
number | Total shareholders' equity. |
currentAssets |
number | Current assets. Null for a period in which the filer's balance sheet reports no current-assets total, as with the unclassified balance sheets of banks, insurers and most REITs. When the filer's filings cannot be checked, the provider's figure is served. |
currentLiabilities |
number | Current liabilities. Null for a period in which the filer's balance sheet reports no current-liabilities total, on the same terms as currentAssets. |
cash |
number | Cash and cash equivalents. Does not include short-term investments. |
debt |
number | Total debt as the provider reports it. On rows from our fallback source: long-term debt, or non-current liabilities when that line is absent, or total minus current liabilities. |
longTermDebt |
number | Long-term debt. |
Cash flow (amounts in reportedCurrency)
| Field | Type | Description |
|---|---|---|
operatingCashFlow |
number | Cash from operations. |
investingCashFlow |
number | Cash from investing. |
financingCashFlow |
number | Cash from financing. |
capitalExpenditure |
number | Capital expenditure, negative as an outflow. A positive provider value is treated as corrupt and served null, along with freeCashFlow. Always null on rows from our fallback source. |
freeCashFlow |
number | operatingCashFlow - abs(capitalExpenditure) when both exist, otherwise the provider's own reported free cash flow, otherwise null. Always null on rows from our fallback source. |
Derived ratios (computed by us from the fields above; null when an input is null)
| Field | Type | Description |
|---|---|---|
grossMargin |
number | grossProfit / revenue, in percent. |
operatingMargin |
number | operatingIncome / revenue, in percent. |
netMargin |
number | netIncome / revenue, in percent. |
currentRatio |
number | currentAssets / currentLiabilities. |
debtToEquity |
number | debt / totalEquity. |
roe |
number | netIncome / totalEquity in percent on annual rows. Null on quarterly history rows: it needs a twelve-month figure, which only /fundamentals carries. |
roa |
number | netIncome / totalAssets in percent, same availability as roe. |
Metadata
| Field | Type | Description |
|---|---|---|
reportedCurrency |
string | Currency of the statement amounts ("USD", "EUR", "KRW", ...). Absent when unknown. |
fetchedAt |
integer | When we fetched the row from the provider, epoch seconds. |
dataSource |
string | Deprecated. Always "". |
preIpoFiling |
object | The SEC filing a pre-IPO quarter was read from; see Pre-IPO quarters under Reading the rows. Null on every other row. |
Always null on history, filled only by /fundamentals
| Fields | Group |
|---|---|
revenueTTM, netIncomeTTM, epsTTM, quartersIncluded |
Trailing twelve months |
peRatio, pbRatio, psRatio |
Price ratios (USD price over home-currency figures, so USD filers only) |
marketCap, currentPrice |
USD market data |
Reading the rows
Two sources. History rows come from our primary statement source, which fills every field
above when the filing carries it. For tickers it does not cover, a fallback source fills the rows
instead, and its rows are marked in the tables:bottomLineNetIncome,sharesOutstanding,capitalExpenditureandfreeCashFloware null on every row,debtis selected as described,
andepsis the diluted figure where one exists. The row does not say which source served it.Corrections from the filing. When the provider's figure for a period contradicts the
company's own SEC filing for that period, and the filing settles which is right, the filing's
figure is served instead:revenue,costOfRevenue,grossProfitandoperatingIncome, when the filer's own lines
for the period are consistent with each other (gross profit plus cost of revenue equals
revenue, and gross profit less operating expenses equals operating income) and disagree with
the provider's. The derived margins follow.weightedAverageSharesBasic,weightedAverageSharesDilutedand the EPS fields of a quarter,
when the provider carried an earlier period's share counts forward into it and divided by them.
On a second or third fiscal quarter the corrected counts can be the filing's year-to-date
averages; the EPS is the quarter's.- The EPS fields and share counts of a fiscal year, when the provider's EPS for the year is
explained by neither its own share count nor the filing's. - The EPS fields and both weighted-average share counts of a first, second or third fiscal
quarter or a fiscal year from roughly the last three (quarters) or five (years) years, when the
company's SEC filing states all four, in US dollars, for that exact period and they agree with each other and
with the period's net income. Fourth quarters keep the provider's figures, because an annual
report states no three-month EPS. A new filing's figures apply once SEC publishes them, usually
within days; until then the provider's stand.
A short reviewed list covers periods whose correction the provider's data cannot settle on its
own; each entry is checked against the filing and stops applying when the provider changes the
period. Corrected rows are not marked. The trailing sums on/fundamentalsadd the corrected
figures.Rows are the provider's, not deduplicated. A provider that republishes a period yields two
rows with the sameperiodEndDate, and a row whose source date could not be parsed carries null
there and sorts last. Both are rare; tolerate both.Pre-IPO quarters. For a small list of recently listed companies, quarterly history includes
a quarter from before the listing that the company filed only as the prior-year comparison column
of a later filing, usually its first 10-Q. That row carriespreIpoFilingnaming the filing, and
holds the income-statement lines the filing reports for the quarter. Its balance-sheet and
cash-flow fields are null, because such a filing carries no quarter-end balance sheet or
three-month cash flow for it. When the provider publishes a row for the same period, that row is
served instead.preIpoFilingis null on every other row, including every annual row.Field Type Description preIpoFiling.formstring SEC form type of the filing, for example 10-Q.preIpoFiling.accessionstring SEC accession number of the filing, 0000000000-00-000000.preIpoFiling.filedDatestring Date the filing was filed, YYYY-MM-DD.preIpoFiling.notestring Where in the filing the figures appear. Share basis. Per-period EPS is served as the provider reports it, apart from the corrections
from the filing above. SentiSense restates it onto a split-adjusted basis for a small list of
named issuers and nowhere else.A provider that restates a company's share counts for a split can leave some older rows' EPS on
the pre-split basis, so those rows contradict themselves. Where that has been checked against the
company's own filing, SentiSense divides the EPS on the affected rows by the split ratio and
marks each one withepsBasisRepair. Share counts and net income are never changed, and no row
of any other issuer is changed.epsBasisRepairis null on almost every row. Null means SentiSense 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: a row whose
issuer is not on the list, or whose figures did not qualify, or for which the split history could
not be read, carries a null marker and is served exactly as the provider reports its EPS.Field Type Description epsBasisRepair.fieldsstring[] Which EPS fields on the row were restated, in the order epsBasic,epsDiluted,eps.epsBasisRepair.multipliernumber Restated value divided by the value the provider reported. Divide by it to recover the provider's figure. epsBasisRepair.splitExecutionDatesstring[] Execution dates of the splits the provider had not applied to this row's EPS, newest first, YYYY-MM-DD.The Cooper Companies (COO) is the worked example. Its share counts are restated for the
four-for-one split of 2024-02-20 back to fiscal 2006 while the provider's EPS is restated only
back to fiscal 2021, so the annual rows through fiscal 2020 carryepsBasisRepairwith amultiplierof 0.25: fiscal 2020 basic EPS is served as 1.215 rather than 4.86, against the
196.4M share count beside it. Fiscal 2021 and fiscal 2022 both carry a null marker. The 7.6x
drop between them is a real earnings move, not a change of basis.epsBasisRepairdescribes per-period EPS only. This repair never changesepsTTMor the other
trailing-twelve-month figures, and the marker never describes a trailing adjustment. Trailing
figures are assembled separately from the per-period rows, and whether they carry a split
adjustment of their own depends on which source served them, so the marker says nothing about a
trailing window that spans one of these seams.
Earnings and share-count fields
epsBasic, epsDiluted, netIncome, bottomLineNetIncome, weightedAverageSharesBasic andweightedAverageSharesDiluted are each the provider's own line, or the filing's where the
corrections described under Reading the rows apply. None is computed from another,
so they are not expected to reconcile arithmetically: netIncome / weightedAverageSharesDiluted
will not generally reproduce any EPS field, because the provider computes EPS from its own numerator
on its own share basis.
netIncome and the EPS fields are consolidated figures that include discontinued operations, whilerevenue and operatingIncome cover continuing operations only, as GAAP presents them. For a company
that has sold or spun off a business, EPS from continuing operations is not served.
bottomLineNetIncome can differ from netIncome in both size and sign. HPE's fiscal 2025 is the
clear case: netIncome is +57,000,000 while bottomLineNetIncome is -59,000,000, alongside a
reported EPS of -0.0446. We publish both as the provider states them and make no claim about how
either reconciles with the EPS fields.
A weighted average is an average over the reporting period, not a count at period end. Neither
share field is a period-end share count, so neither is a correct input to a market capitalisation
or a book value per share.
Deprecated:
sharesOutstandingThis field stops being populated on 2026-12-15. It is not a shares-outstanding count despite
its name, and it means different things on different responses: the diluted weighted average
(or the basic one where no diluted figure exists) on history rows and on latest periods served
from the statement source, amarketCap / currentPriceestimate on latest periods that carry
market data, and null on fallback-source history rows and on some explicit-period requests.
That ambiguity is why it is being retired rather than redefined.Migrate to
weightedAverageSharesDiluted, falling back toweightedAverageSharesBasicwhen it
is null. On every row where the old field was a share count, that gives the same number. It does
not reproduce themarketCap / currentPriceestimate: if your code depends on that one, usemarketCapandcurrentPricedirectly.
GET /fundamentals/historical/revenue
Returns a lightweight income-statement series (revenue, gross profit, operating income, net
income, EPS) per fiscal quarter or year, wrapped in dataPoints with count and reason
(dataSource is deprecated and always empty). Covers recent periods only (roughly the last three
to four years). For longer history or the balance sheet and cash flow, use /fundamentals/history.grossProfit is null for a period whose cost of revenue fails the consistency check described
under costOfRevenue on /fundamentals/history. Where /fundamentals/history serves a figure
corrected from the company's filing (see Corrections from the filing under
Reading the rows), this series serves the same figure for that period.
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/historical/revenue?ticker=AAPL"
Short Interest & Float
GET /short-interest
Returns twice-monthly short interest data from FINRA for a stock, newest settlement date first.
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/short-interest?ticker=AAPL&limit=24"
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
string | Yes | - | Stock ticker symbol |
limit |
integer | No | 24 | Maximum number of settlement dates to return |
Response:
| Field | Type | Description |
|---|---|---|
ticker |
string | Uppercase ticker symbol |
count |
integer | Number of entries in dataPoints |
dataPoints[] |
array | One entry per settlement date, newest first |
dataPoints[].shortInterest |
number | Shares sold short and not yet covered, in shares |
dataPoints[].daysToCover |
number | shortInterest divided by avgDailyVolume |
dataPoints[].avgDailyVolume |
number | Average daily trading volume over the period, in shares |
dataPoints[].settlementDate |
string | Settlement date (ISO YYYY-MM-DD) |
{
"ticker": "AAPL",
"dataPoints": [
{ "shortInterest": 120000000, "daysToCover": 2.5, "avgDailyVolume": 48000000, "settlementDate": "2026-01-15" }
],
"count": 1
}
A ticker with no short interest data returns 200 with an empty dataPoints array and count: 0.
GET /float
Returns the free float: shares available for public trading.
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/float?ticker=AAPL"
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
string | Yes | - | Stock ticker symbol |
Response:
| Field | Type | Description |
|---|---|---|
ticker |
string | Uppercase ticker symbol |
freeFloat |
number | null | Free float, in shares. 0 means the symbol has no free float, as for funds such as SPY and QQQ |
freeFloatPercent |
number | null | Free float as a percentage of total shares, in percentage points (92.1 means 92.1%) |
effectiveDate |
string | null | Date the float figure applies to, as YYYY-MM-DD or YYYY-MM-DD HH:mm:ss depending on the data source |
{ "ticker": "AAPL", "freeFloat": 14000000000, "freeFloatPercent": 92.5, "effectiveDate": "2026-01-15" }
A ticker with no float data returns 200 with freeFloat, freeFloatPercent and effectiveDate all null. For share counts, use weightedAverageSharesDiluted and weightedAverageSharesBasic on GET /fundamentals/history.
GET /short-volume
Returns daily short sale volume for a stock, newest date first.
curl -H "X-SentiSense-API-Key: $SENTISENSE_API_KEY" \
"https://app.sentisense.ai/api/v1/stocks/short-volume?ticker=AAPL&limit=90"
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
string | Yes | - | Stock ticker symbol |
limit |
integer | No | 90 | Maximum number of trading days to return |
Response:
| Field | Type | Description |
|---|---|---|
ticker |
string | Uppercase ticker symbol |
count |
integer | Number of entries in dataPoints |
dataPoints[] |
array | One entry per trading day, newest first |
dataPoints[].shortVolume |
number | Shares sold short that day, in shares |
dataPoints[].totalVolume |
number | Total shares traded that day on the reporting venues, in shares; not consolidated market volume |
dataPoints[].shortVolumeRatio |
number | shortVolume as a share of totalVolume, in percentage points (45.2 means 45.2%) |
dataPoints[].date |
string | Trading day (ISO YYYY-MM-DD) |
{
"ticker": "AAPL",
"dataPoints": [
{ "shortVolume": 7000000, "totalVolume": 15500000, "shortVolumeRatio": 45.16, "date": "2026-01-15" }
],
"count": 1
}
A ticker with no short volume data returns 200 with an empty dataPoints array and count: 0.
Quote Snapshot
GET /{ticker}/quote
Returns a single-call aggregate snapshot combining the latest price (delayed 15 minutes), today's OHLC, 52-week range, market cap, and key fundamentals. Designed for detail pages that need all key stats in one request.
Authentication: API key required | Rate limit: standard quota
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/quote"
Response object:
| Field | Type | Description |
|---|---|---|
ticker |
string | Ticker symbol |
currentPrice |
number|null | Regular-session price, delayed 15 minutes. During RTH (09:30 to 16:00 ET): the most recent regular-session value. Otherwise: most recent regular-session close. |
change |
number|null | currentPrice change vs previousClose |
changePercent |
number|null | currentPrice change percentage vs previousClose |
volume |
number|null | Volume for the current session |
open |
number|null | Opening price for the current session |
dayHigh |
number|null | Intraday high |
dayLow |
number|null | Intraday low |
previousClose |
number|null | Previous session close |
week52High |
number|null | 52-week high |
week52Low |
number|null | 52-week low |
marketCap |
number|null | Market capitalization (USD) |
peRatio |
number|null | Trailing P/E ratio |
epsTTM |
number|null | Earnings per share (TTM) |
dividendYield |
number|null | Annual dividend yield (decimal, e.g. 0.005) |
movingAverage200Day |
number|null | 200-day simple moving average of daily closes. null when fewer than 200 trading days of history exist (e.g. a recent IPO). |
reportedCurrency |
string|null | Currency epsTTM is reported in ("USD", "EUR", "KRW", ...), as filed. Same field and same meaning as on the fundamentals endpoints. Absent when no fundamentals are available for the ticker. |
timestamp |
number|null | When this response was served (epoch milliseconds). Not the age of the price: it tracks the current clock regardless of how old the value is. |
priceAsOf |
number | absent | When the market data behind currentPrice is from (epoch milliseconds). This is the field to read for freshness. Omitted outside regular hours, and whenever the upstream data is not dated, so treat its absence as "unknown" rather than "fresh". |
extendedHours |
object | null | Extended-hours view (pre-market or after-hours). Absent during RTH, overnight, and weekends. Same shape as on /price: { session, price, change, changePercent }. |
listingStatus |
string | absent | "DELISTED" or "PENDING_DELISTING". Present only when the symbol is delisted or pending delisting, absent otherwise. |
delistedDate |
string | absent | ISO date (YYYY-MM-DD) trading stopped. Present only alongside listingStatus: "DELISTED". |
delistingReason |
string | absent | One of acquired, take_private, bankruptcy, exchange_rule, merged. Present only alongside listingStatus: "DELISTED". |
All fields except ticker are nullable. Render "--" or hide the row when a field is absent.
Null fields are omitted from the JSON. A null field is left out of the response body entirely rather than serialized as null, so the key count varies by ticker. Read defensively rather than assuming a key is present.
Foreign filers omit reportedCurrency, epsTTM and peRatio. On foreign ADR filers such as ASML and TM those three fields are absent, while price fields, marketCap and dividendYield are served normally. This is the same cross-currency rule the fundamentals endpoints follow: currentPrice is the USD ADR price and the filer's earnings are in home currency, so a trailing P/E would mix two currencies. We withhold it rather than publish a wrong number. Do not fill the gap by dividing currentPrice by a non-USD epsTTM.
Delisted symbols keep quoting their last trade. When listingStatus reads "DELISTED", every price field above (including open, dayHigh, dayLow, previousClose and volume) describes the final trading session. priceAsOf is the close of that session, which can fall a day or more before delistedDate, and extendedHours is absent. timestamp remains the serve time, so do not read it as the age of the price. The same three listing fields appear on GET /price and GET /{ticker}/profile.
Example response (after-hours):
{
"ticker": "AAPL",
"currentPrice": 213.45,
"change": 1.23,
"changePercent": 0.58,
"volume": 48203100,
"open": 212.10,
"dayHigh": 214.20,
"dayLow": 211.80,
"previousClose": 212.22,
"week52High": 237.23,
"week52Low": 164.08,
"marketCap": 3280000000000,
"peRatio": 32.1,
"epsTTM": 6.65,
"dividendYield": 0.0044,
"movingAverage200Day": 198.42,
"reportedCurrency": "USD",
"timestamp": 1745600000000,
"extendedHours": {
"session": "post",
"price": 214.10,
"change": 0.65,
"changePercent": 0.30
}
}
ETF tickers: This endpoint is stock-only. Calling it with an ETF ticker (e.g. VTI, SPY) returns 400 ticker_is_etf with a pointer to GET /etfs/{ticker}/quote which returns AUM, expense ratio, NAV, and inception date instead of market cap / P/E / EPS. The error body also carries a seeInstead array holding that exact path, so a client can follow it without string-matching the message:
{
"error": "ticker_is_etf",
"message": "SPY is an ETF; use /api/v1/etfs/SPY/quote",
"seeInstead": ["/api/v1/etfs/SPY/quote"]
}
Rate-limit note: Cached for 15 seconds server-side. Each call still counts toward your monthly quota.
Company KPIs
A KPI is a per-company key performance indicator series: the operating numbers a company reports about itself, quarter after quarter, in a chartable shape. Financial statements describe what every company reports; KPIs describe what a specific company reports. The set covers GAAP line items and the company-specific non-GAAP metrics that move a stock, such as iPhone unit sales, Tesla deliveries, AWS revenue, and Netflix paid net adds. Every series is curated per company from earnings filings and press releases, and carries a citation to the filing it came from.
The endpoints below cover the whole surface: GET /with-kpis enumerates coverage, GET /{ticker}/kpis/types lists one company's metrics, and GET /{ticker}/kpis returns the series. The reference for each follows this section.
Worked examples: the Company KPI API guide.
The three-step KPI workflow
Discovery first, then metadata, then data. Steps 1 and 2 are Discovery tier: an API key is required for identity, but neither call consumes monthly quota, so a client can refresh the shape of its universe far more often than it fetches series payloads. Only step 3 is quota-gated and PRO-gated.
Step 1: discover which companies have coverage. Call once at startup and cache it. Enumerating coverage is the supported alternative to probing tickers one at a time and collecting 404s.
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/with-kpis"
{
"count": 947,
"tickers": [
{ "ticker": "AAPL", "companyName": "Apple Inc.", "lastUpdated": "2026-01-30", "kpiCount": 8 },
{ "ticker": "ABBV", "companyName": "AbbVie Inc.", "lastUpdated": "2026-01-25", "kpiCount": 6 }
]
}
Step 2: list one company's KPI types. Metadata tuples only, with no series payload attached. Use it to decide what is worth rendering, or to let an agent choose, before committing to the heavy call.
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/kpis/types"
[
{ "id": "iphone_revenue", "name": "iPhone Revenue", "category": "product_revenue", "chartType": "bar" },
{ "id": "services_revenue", "name": "Services Revenue", "category": "segment_revenue", "chartType": "line" }
]
Step 3: fetch the series. The endpoint takes only the ticker and returns every curated series for it; select the ones you need by id from Step 2. Points are ordered newest to oldest: the first element is the most recently reported period.
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/kpis"
{
"isPreview": false,
"previewReason": null,
"data": {
"ticker": "AAPL",
"companyName": "Apple Inc.",
"cik": "0000320193",
"lastUpdated": "2026-01-30",
"kpis": [
{
"id": "iphone_revenue",
"name": "iPhone Revenue",
"category": "product_revenue",
"unit": "USD",
"displayFormat": "currency_abbreviated",
"chartType": "bar",
"values": [
{ "period": "Q4 FY2025", "date": "2025-09-27", "value": 50000000000, "isEstimate": null },
{ "period": "Q1 FY2026", "date": "2025-12-27", "value": 85000000000, "isEstimate": null }
],
"sourceRef": "Apple 8-K Q1 FY2026 press release",
"discontinued": false,
"discontinuedNote": null
}
]
}
}
Example values throughout this section are illustrative, not live readings.
GET /{ticker}/kpis
Returns company-specific KPI time-series for a ticker. KPIs are curated GAAP and non-GAAP metrics extracted from earnings filings and press releases (e.g. iPhone unit sales, Tesla deliveries, AWS revenue, Netflix paid net adds).
Authentication: API key required on every call; PRO for the series data. A free key receives isPreview: true with the company metadata and an empty kpis list, which is enough to detect coverage and gate the UI. Calls without a key return 401 api_key_required.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
path | Yes | - | Stock ticker symbol |
Coverage today: near-complete for the S&P 500 plus an extended universe of 900+ tickers, and growing. Entries can briefly show kpiCount: 0 while curation for a newly added company is in flight; skip those when enumerating. Roadmap: coverage extending to the long-tail of US tickers; some tickers may return 404 Not Found until curated. Use GET /with-kpis to enumerate the current set.
Example Request:
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/kpis"
Response Schema (envelope):
| Field | Type | Description |
|---|---|---|
isPreview |
boolean | true when the caller is on the FREE tier |
previewReason |
string | "PRO_REQUIRED" or null |
upgrade |
object | Present only when isPreview is true. Carries plan, message, price, url and relay: surface message and url to your user in one line, then continue with the preview data |
data.ticker |
string | Stock ticker |
data.companyName |
string | Company name |
data.cik |
string | SEC Central Index Key (when available) |
data.lastUpdated |
string | ISO date of the last KPI refresh |
data.kpis |
array of KpiSeries |
Time-series objects (PRO only; empty in preview) |
KpiSeries object:
| Field | Type | Description |
|---|---|---|
id |
string | Stable per-ticker identifier, e.g. "iphone_revenue" |
name |
string | Human-readable name, e.g. "iPhone Revenue" |
category |
string | Logical category: "product_revenue", "segment_revenue", "unit_economics", etc. |
unit |
string | Unit of measurement: "USD", "units", "subscribers", "%", etc. |
displayFormat |
string | Display hint: "currency_abbreviated", "number_abbreviated", "percent", etc. |
chartType |
string | Default chart type: "bar" or "line" |
values |
array of KpiDataPoint |
Time-series data points, newest to oldest (first element is most recent) |
sourceRef |
string | Citation for the source filing |
discontinued |
boolean or null | true when the company has stopped reporting this metric; null or false otherwise |
discontinuedNote |
string | Optional human-readable note about discontinuation |
KpiDataPoint object:
| Field | Type | Description |
|---|---|---|
period |
string | Fiscal period label, e.g. "Q2 FY2026" |
date |
string | ISO date of the period close, e.g. "2025-12-27" |
value |
number | Numeric value for the period |
isEstimate |
boolean|null | true for preliminary or estimated values; usually null |
Example Response (truncated):
{
"isPreview": false,
"previewReason": null,
"data": {
"ticker": "AAPL",
"companyName": "Apple Inc.",
"cik": "0000320193",
"lastUpdated": "2026-04-30",
"kpis": [
{
"id": "iphone_revenue",
"name": "iPhone Revenue",
"category": "product_revenue",
"unit": "USD",
"displayFormat": "currency_abbreviated",
"chartType": "bar",
"values": [
{ "period": "Q1 FY2025", "date": "2024-12-28", "value": 69702000000, "isEstimate": null },
{ "period": "Q2 FY2025", "date": "2025-03-29", "value": 46841000000, "isEstimate": null },
{ "period": "Q3 FY2025", "date": "2025-06-28", "value": 39286000000, "isEstimate": null },
{ "period": "Q4 FY2025", "date": "2025-09-27", "value": 49025000000, "isEstimate": null },
{ "period": "Q1 FY2026", "date": "2025-12-27", "value": 85269000000, "isEstimate": null }
],
"sourceRef": "Apple 8-K Q1 FY2026 press release",
"discontinued": false,
"discontinuedNote": null
}
]
}
}
GET /with-kpis
Lists every ticker with curated KPI coverage, sorted alphabetically. Builder discovery use case: render a supported-tickers page or seed a watchlist without 404-probing one ticker at a time.
Authentication: API key required. No monthly quota cost (Discovery tier: the call registers identity for abuse tracking but does not burn the per-month quota; rate-limit-per-minute still applies).
Parameters: None.
Example Request:
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/with-kpis"
Response Schema:
| Field | Type | Description |
|---|---|---|
count |
int | Total number of tickers with curated KPI coverage |
tickers |
array of KpiCoverageEntry |
Listing sorted alphabetically by ticker |
KpiCoverageEntry object:
| Field | Type | Description |
|---|---|---|
ticker |
string | Stock ticker |
companyName |
string | Company name |
lastUpdated |
string | ISO date of the last KPI refresh for this ticker |
kpiCount |
int | Number of distinct KPI series available for this ticker |
Example Response (truncated):
{
"count": 947,
"tickers": [
{ "ticker": "A", "companyName": "Agilent Technologies, Inc.", "lastUpdated": "2026-04-12", "kpiCount": 5 },
{ "ticker": "AAPL", "companyName": "Apple Inc.", "lastUpdated": "2026-04-30", "kpiCount": 8 },
{ "ticker": "ABBV", "companyName": "AbbVie Inc.", "lastUpdated": "2026-04-22", "kpiCount": 6 }
]
}
GET /{ticker}/kpis/types
Lists the KPI metadata tuples available for a ticker without paying the cost of the full series payload. Mirrors the /api/v1/insights/stock/{ticker}/types precedent. Useful for letting an agent or UI decide which KPIs to render before fetching the data.
Authentication: API key required. No monthly quota cost (Discovery tier).
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
path | Yes | - | Stock ticker symbol |
Example Request:
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/kpis/types"
Response Schema (bare array):
| Field | Type | Description |
|---|---|---|
id |
string | Stable per-ticker identifier |
name |
string | Human-readable name |
category |
string | Logical category |
chartType |
string | Default chart type: "bar" or "line" |
Example Response:
[
{ "id": "iphone_revenue", "name": "iPhone Revenue", "category": "product_revenue", "chartType": "bar" },
{ "id": "services_revenue", "name": "Services Revenue", "category": "segment_revenue", "chartType": "line" },
{ "id": "mac_revenue", "name": "Mac Revenue", "category": "product_revenue", "chartType": "bar" }
]
Returns 404 Not Found when the ticker has no curated KPIs.
Reading a KPI point
Periods are fiscal, not calendar. period is a display label such as "Q1 FY2026"; date is the ISO date on which that period closed. The two routinely disagree with the calendar: a fiscal Q1 can close in December. Sort and align on date, label with period, and do not assume a fiscal quarter maps to a calendar quarter when comparing two companies.
Units live on the series, not on the point. value is a raw number. Its meaning comes from unit on the parent series ("USD", "units", "subscribers", "%"), and displayFormat is the matching rendering hint (currency_abbreviated, number_abbreviated, percent). Read the two together rather than inferring a unit from the series name. chartType carries the intended default rendering, bar or line.
Points run newest to oldest. The first element is the most recently reported period, so a sequential delta is the first two elements, and a year-over-year delta is the first element against the one four positions later (index 0 against index 4) when the series has no gaps. Series lengths vary by company and metric; check the length before indexing.
Two flags change how a series should be displayed. isEstimate is true for a preliminary or estimated value and is usually null otherwise. discontinued is true once a company stops reporting a metric, with an optional discontinuedNote; a discontinued series remains valid history but should not sit on a live dashboard as though a new print is coming.
Every series carries sourceRef, a citation for the filing the numbers came from. Surface it wherever a user might ask where a number originated.
Dual-class tickers resolve server-side. KPI endpoints accept the secondary share class and resolve it to the curated primary, so GOOG reaches Alphabet's series and BRK-B reaches Berkshire's. See Ticker symbols for the aliasing rules, including the pairs that are tracked separately rather than aliased.
Patterns for builders
Quarter-over-quarter and year-over-year deltas. The series arrives ordered newest first, so deltas are arithmetic rather than an extra request: the first two points for the sequential move, the first against the point four positions later for the annual move. Ranking a watchlist by acceleration in a company-specific metric surfaces moves that a price screen does not.
Earnings-eve reads. Combine GET /api/v1/calendar/earnings with a watchlist to find which companies report next, then load their KPI series to show which operating numbers matter and how they have trended into the print. Because coverage discovery and KPI types cost no monthly quota, the watchlist intersection can refresh far more often than the series fetch.
Pairing KPIs with sentiment. Fetch the reported operating number from the KPI endpoints and the market's reading from GET /api/v2/metrics/entity/{entityId}/metric/{metricType}, where metricType is mentions, sentiment, sentisense, or social_dominance. Metric points are time-ascending with a flat value scalar, so they plot directly against a KPI series. A core metric accelerating while sentiment fades, or the reverse, is a divergence a price chart does not show.
Cache by reporting cadence. Most KPI series change only when a company files, which for the majority of metrics means once a quarter. Cache the coverage list and the type list on a daily cadence, and refresh a company's series around its reporting date rather than on every page view. lastUpdated on both the coverage entry and the series payload tells you when a refresh actually landed.
Sentiment
GET /{ticker}/sentiment
Returns the stock's headline sentiment picture in one call: the proprietary SentiSense Score, its
30-day regime and direction, a daily sparkline, where the conversation is happening by source, the
stories driving it, and curated peer tickers.
This is the endpoint the Developer Console hands you as your first call.
Authentication: API key required. Available in full on the Free tier.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ticker |
path | Yes | - | Stock ticker symbol |
Example Request:
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/sentiment"
When there is nothing to return: a 404 whose error is either entity_not_found (no stock is tracked under that symbol; the body carries up to three suggestions, so resolve with GET /api/v1/kb/entities/search?q= and retry) or no_coverage (the symbol is tracked, we hold no sentiment record for it, and a different spelling will not help). See Two kinds of 404.
Response: { isPreview, previewReason, data }. Every field below lives under data. The endpoint is available in full on every tier and still uses the wrapper, so an API-key caller always gets isPreview: false and previewReason: null. Unwrap first: the Score is at data.sentisenseScore, and reading sentisenseScore off the root returns nothing.
Response Schema:
Field (under data) |
Type | Description |
|---|---|---|
ticker |
string | Ticker symbol |
companyName |
string | Company name |
asOf |
string | ISO date (YYYY-MM-DD) the data is current as of |
sentisenseScore |
number or null | Today's SentiSense Score (sentiment x mentions composite, unbounded). Null until today's reading lands, see the note below |
sentisenseScoreAvg30d |
number | 30-day average Score, the stable regime figure |
sentisenseScoreDelta30d |
number | Change in the Score over 30 days |
scoreLabel |
string | Seven-band label of the 30-day average: "Strong Bearish", "Bearish", "Slightly Bearish", "Neutral", "Slightly Bullish", "Bullish" or "Strong Bullish" |
direction |
string | "Bullish", "Neutral" or "Bearish", from the 30-day average |
latestDirection |
string or null | Same three bands, from today's read. Null in lockstep with sentisenseScore |
trend |
string | "UP", "DOWN" or "FLAT" |
scoreSparkline |
number[] | Daily Score series |
mentions |
number or null | Mention volume of the latest New York daily bucket with data: today's once it lands, otherwise an earlier day, which narrative and faq name; null when there is none |
mentionsAvg30d |
number | 30-day average mentions per day |
socialDominance |
number | Latest share of voice, as a fraction (0.021 = 2.1%) |
bySource[] |
array | Per-source tone, loudest source first: source, direction, mentionShare (whole-number percent; each share is rounded independently, so the array can sum to 99 or 101), value (exact polarity, -1 to 1) |
relatedTickers[] |
array | Curated peer tickers: ticker, name |
drivers[] |
array | Top story drivers: title, tone (-1 to 1) |
narrative |
string | Short plain-language summary of why the Score sits where it does |
faq[] |
array | Question and answer pairs covering the common asks for this ticker |
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.
Example Response:
{
"isPreview": false,
"previewReason": null,
"data": {
"ticker": "AAPL",
"companyName": "Apple Inc.",
"asOf": "2026-08-02",
"sentisenseScore": 41.2,
"sentisenseScoreAvg30d": 33.8,
"sentisenseScoreDelta30d": 7.4,
"scoreLabel": "Bullish",
"direction": "Bullish",
"latestDirection": "Bullish",
"trend": "UP",
"scoreSparkline": [28.1, 30.4, 31.9, 35.2, 41.2],
"mentions": 1840,
"mentionsAvg30d": 1512,
"socialDominance": 0.081,
"bySource": [
{ "source": "News", "direction": "Bullish", "mentionShare": 58, "value": 0.1889 },
{ "source": "Reddit", "direction": "Neutral", "mentionShare": 21, "value": 0.0428 },
{ "source": "X", "direction": "Bullish", "mentionShare": 10, "value": 0.1809 }
],
"relatedTickers": [ { "ticker": "MSFT", "name": "Microsoft Corporation" } ],
"drivers": [ { "title": "Apple raises services guidance", "tone": 0.44 } ],
"narrative": "Sentiment has strengthened over the past month, led by news coverage.",
"faq": [ { "question": "Is AAPL bullish or bearish?", "answer": "..." } ]
}
}
Returns 404 Not Found when the ticker has no sentiment coverage.
This is the single-stock read. Two market-wide counterparts live in the Market Mood API: /api/v1/sentiment/sectors ranks the 11 GICS sectors against the market's own tone, and /api/v1/sentiment/breadth gives the bullish/neutral/bearish share of the roughly 1,000 covered stocks, the sentiment analogue of an advance/decline line.
Note on the response envelope: search-engine crawlers receive the same envelope withisPreview: true and each per-source value set to null; direction and mention share are always
present. API-key callers on any tier receive the full payload with isPreview: false.
Try It
Test endpoints directly from your browser. Paste your API key once: it's saved locally and shared across all widgets. Get a free key
GET/api/v1/stocks/
List all available stock tickers
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks"GET/api/v1/stocks/detailed
All stocks with company details
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/detailed"GET/api/v1/stocks/popular
Popular stock tickers
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/popular"GET/api/v1/stocks/popular/detailed
Popular stocks with details
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/popular/detailed"GET/api/v1/stocks/images
Batch company logo URLs
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/images?tickers=AAPL%2CTSLA"GET/api/v1/stocks/descriptions
Company profiles with branding
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/descriptions?tickers=AAPL%2CTSLA"GET/api/v1/stocks/{ticker}/similar
Peer/similar stocks
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/similar"GET/api/v1/stocks/{ticker}/profile
Company profile (CEO, sector, etc.)
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/profile"GET/api/v1/stocks/{ticker}/entities
Related ontology entities
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/entities"GET/api/v1/stocks/{ticker}/graph
Knowledge graph around a stock
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/graph"GET/api/v1/stocks/{ticker}/ai-summary
AI-generated stock analysis report
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/ai-summary"GET/api/v1/stocks/{ticker}/metrics/{metricType}/breakdown
Sentiment/mention metrics breakdown
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/metrics/sentiment/breakdown"GET/api/v1/stocks/price
Latest price for a single stock, delayed 15 minutes
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/price?ticker=AAPL"GET/api/v1/stocks/prices
Latest prices for multiple stocks, delayed 15 minutes
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/prices?tickers=AAPL%2CTSLA%2CNVDA"GET/api/v1/stocks/chart
Historical OHLCV chart data
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/chart?ticker=AAPL&timeframe=1M"GET/api/v1/stocks/market-status
Current market open/closed status
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/market-status"GET/api/v1/stocks/fundamentals
Financial statement data
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals?ticker=AAPL"GET/api/v1/stocks/fundamentals/periods
Available fiscal periods
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/periods?ticker=AAPL"GET/api/v1/stocks/fundamentals/current
Trailing P/E, P/S and EPS profile
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/current?ticker=AAPL"GET/api/v1/stocks/fundamentals/history
Multi-period statement history (up to 40 quarters or 20 years)
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/history?ticker=AAPL"GET/api/v1/stocks/fundamentals/historical/revenue
Historical revenue data
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/fundamentals/historical/revenue?ticker=AAPL"GET/api/v1/stocks/short-interest
Short interest metrics
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/short-interest?ticker=AAPL"GET/api/v1/stocks/float
Float information
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/float?ticker=AAPL"GET/api/v1/stocks/short-volume
Short volume data
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/short-volume?ticker=AAPL"GET/api/v1/stocks/{ticker}/quote
Aggregate quote snapshot (price, OHLC, 52W, fundamentals)
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/quote"GET/api/v1/stocks/{ticker}/kpis
Company-specific KPI time-series (PRO)
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/kpis"GET/api/v1/stocks/with-kpis
List every ticker with curated KPI coverage (key required, no quota cost)
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/with-kpis"GET/api/v1/stocks/{ticker}/kpis/types
Lightweight KPI metadata tuples for a ticker (key required, no quota cost)
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/kpis/types"GET/api/v1/stocks/{ticker}/sentiment
SentiSense Score, 30-day direction, per-source tone, and story drivers
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/stocks/AAPL/sentiment"