# Earnings Analysis API

> The earnings lifecycle as one API family: who reports (calendar), what management changed in its SEC filings (risk-factor diffs), the per-quarter analysis of what was actually reported, and the AI takeaway (insights).

Base URL: `https://app.sentisense.ai/api/v1/`
Tier: PRO (free preview available)

All API access requires an API key via the `X-SentiSense-API-Key` header. Keys look like `ss_live_...`.

> SDKs: [Python](https://github.com/SentiSenseApp/sentisense#earnings) · [Node](https://github.com/SentiSenseApp/sentisense-node#earnings)

## Overview

An earnings event is not a single moment, it is a short lifecycle, and this API family follows it end to end. First you know who reports and when: the **Earnings Calendar**. Then you read what management changed in its own words, through deterministic diffs of the risk-factor sections of consecutive SEC filings: **What Changed**. Then, once the company reports, you read the quarter itself: the **Earnings Analysis Report**, plus the reported numbers (**fundamentals and company KPIs**) and the takeaway as AI-generated signals (**Insights**).

Three endpoints are documented in full below. The Calendar, Fundamentals and KPIs, and Insights members of the family already have their own reference pages and are summarized here with links, not restated.

**In this family:**
- **What Changed** (this page): risk-factor (Item 1A) diffs of consecutive 10-K and 10-Q filings, with added, removed, and modified passages and a materiality score.
- **Earnings Analysis Report** (this page): the per-quarter readout, one object per fiscal quarter, carrying the headline, KPI highlights with year-over-year deltas, guidance language, and a summary of the earnings call.
- **Recently reported** (this page): the cross-ticker view of which covered companies reported in a recent window.
- **Earnings Calendar**: forward-looking report dates with session timing, fiscal quarter, confirmation status, and consensus EPS.
- **Reported Financials and KPIs**: standardized financial-statement data plus curated company KPIs.
- **Earnings Insights**: AI-generated signals, including earnings-driven signal types.

**Where the quarter is the unit.** The analysis is organized by fiscal quarter, and everything else attaches to one: a filing diff belongs to the quarter it covers, and consensus EPS from the Calendar is the anchor a headline beats or misses. Build a quarter view by pairing `GET /api/v1/stocks/{ticker}/earnings-summaries` with the filings that fall near its `reportDate`, rather than treating filings and results as two unrelated lists.

---

## What Changed: SEC risk-factor diffs

Risk-factor language is written by lawyers and changes reluctantly. When a company rewrites large parts of that section, it is often the earliest public signal of a newly disclosed risk. What Changed compares the Item 1A Risk Factors section of each new 10-K or 10-Q against the prior filing of the same form (10-K vs prior 10-K, 10-Q vs prior 10-Q) and returns excerpts of the passages that were added, removed, or modified, along with the new key terms.

**Use cases:**
- Detect newly disclosed risk factors shortly after a 10-K or 10-Q is filed.
- Rank a watchlist by how heavily each company revised its risk language this quarter.
- Pull the before and after excerpts and the new terms for research or summarization.
- Cross-reference filing changes with sentiment, insider trading, and analyst revisions.

**Coverage:** roughly 500 large-cap US companies, including 99% of the S&P 500 plus a set of widely followed software and semiconductor names outside the index. It tracks the Item 1A Risk Factors section of **10-K** (annual) and **10-Q** (quarterly) filings and returns up to about **three sequential filing-to-filing comparisons per form**: the annual filings back to 2023 and roughly the last year of quarterly filings. Nearly every comparison returns full `diff` detail. The one structural exception is the earliest filing held for a given form: it has no prior filing to compare against, so it returns the per-filing summary fields (materiality score, the no-material-changes flag, and the EDGAR link) without the `diff` object. Treat `diff` as optional on every entry rather than assuming it is present. New filings are typically reflected within 48 hours of appearing on the SEC public filing system. Coverage is expanding over time.

Tickers outside the covered set return a **successful, empty response** (`200` with an empty `data` array), not an error. Use canonical ticker symbols: `GOOGL` (not `GOOG`) and `BRK.B` (not `BRK-B`).

**Free preview:** the per-filing summary (form type, filing and report dates, section, materiality score, no-material-changes flag, EDGAR link) with `totalCount`. The full diff detail (changed passages, ratios, and new terms) is PRO-only.

## GET /api/v1/stocks/{ticker}/what-changed

Returns the ticker's diffed filings, newest first. Each entry compares one filing's Risk Factors section against the prior filing of the same form.

**Authentication:** PRO required for diff detail. Free users receive the summary fields and `totalCount`.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `ticker` | path | Yes | - | Stock ticker symbol, canonical form (e.g. `AAPL`) |
| `form` | query | No | both | Filter to `10-K` or `10-Q` |
| `limit` | query | No | 4 | Max entries returned (1 to 12). Values above 12 are capped at 12. Values below 1 are rejected with `400 invalid_limit`. |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/stocks/AAPL/what-changed?limit=1"
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `isPreview` | boolean | `true` when the caller is on the FREE tier |
| `previewReason` | string | `"PRO_REQUIRED"` or `null` |
| `totalCount` | integer | Preview responses only: total diffed filings available |
| `data` | array | Filing comparisons, newest first (see below) |

**Filing entry:**

| Field | Type | Description |
|-------|------|-------------|
| `ticker` | string | Canonical ticker |
| `formType` | string | `10-K` or `10-Q` |
| `accessionNo` | string | Accession number of the newer filing |
| `filedAt` | string | Filing date, `YYYY-MM-DD` |
| `reportDate` | string | Fiscal period the filing covers, `YYYY-MM-DD` |
| `section` | string | Compared section, `Risk Factors` (Item 1A) today |
| `materialityScore` | number | A 0 to 1 measure of how much the section changed versus the prior filing of the same form |
| `noMaterialChanges` | boolean | `true` when the filer states the section has no material changes (common in 10-Qs) |
| `edgarUrl` | string | Link to the filing on the SEC public filing system |
| `diff` | object | PRO only: full diff detail (see below) |

**Diff detail (PRO):**

| Field | Type | Description |
|-------|------|-------------|
| `blocks` | array | Changed regions: `{op, similarity, oldExcerpt, newExcerpt, oldParagraphs, newParagraphs}` where `op` is `added`, `removed`, or `modified`. `oldExcerpt` and `newExcerpt` are capped at 400 characters and end with `...` when truncated; a block spanning many paragraphs still returns one bounded excerpt |
| `paragraphsAdded` | integer | Paragraphs with no counterpart in the prior filing |
| `paragraphsRemoved` | integer | Prior-filing paragraphs that were dropped |
| `paragraphsModified` | integer | Paragraphs rewritten in place |
| `charsAdded` / `charsRemoved` | integer | Character-level change volume |
| `changedRatio` | number | Share of the section affected by changes, 0 to 1 |
| `noveltyRatio` | number | Share of the new section that is genuinely new language, 0 to 1 |
| `materialityScore` | number | Composite of the changed and novelty ratios, 0 to 1 |
| `topNewTerms` | array | Most distinctive terms appearing in the new filing but not the prior one |
| `identical` | boolean | `true` when the sections match after normalization |
| `noMaterialChanges` | boolean | Mirrors the entry-level flag |

**Example Response (PRO, truncated):**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": [
    {
      "ticker": "AAPL",
      "formType": "10-Q",
      "accessionNo": "0000320193-26-000020",
      "filedAt": "2026-07-31",
      "reportDate": "2026-06-27",
      "section": "Risk Factors",
      "materialityScore": 0.769,
      "noMaterialChanges": false,
      "edgarUrl": "https://www.sec.gov/Archives/edgar/data/320193/000032019326000020/0000320193-26-000020-index.htm",
      "diff": {
        "blocks": [
          {
            "op": "modified",
            "similarity": 0.722,
            "oldExcerpt": "The Company's business, reputation, results of operations, financial condition and stock price can be materially and adversely affected by a number of factors, whether currently known or unknown, including those described in Part I, Item 1A of the 2025 Form 10-K under the heading \"Risk Factors.\" Except as set forth below, there have been no material changes to the Company's risk factors since the ...",
            "newExcerpt": "The Company's business, reputation, results of operations, financial condition and stock price can be materially and adversely affected by a number of factors, whether currently known or unknown, including those described in Part I, Item 1A of the 2025 Form 10-K and Part II, Item 1A of the Form 10-Q for the quarter ended March 28, 2026 (the \"second quarter 2026 Form 10-Q\"), in each case under the ...",
            "oldParagraphs": 1,
            "newParagraphs": 1
          }
        ],
        "paragraphsAdded": 0,
        "paragraphsRemoved": 0,
        "paragraphsModified": 13,
        "charsAdded": 7214,
        "charsRemoved": 10213,
        "changedRatio": 0.912,
        "noveltyRatio": 0.2299,
        "materialityScore": 0.769,
        "topNewTerms": ["obtain", "depend", "quantities", "commercially", "computing"],
        "identical": false,
        "noMaterialChanges": false
      }
    }
  ]
}
```

FREE tier: same shape with `isPreview: true`, `previewReason: "PRO_REQUIRED"`, a `totalCount` of the diffed filings available, and each entry carrying the summary fields without the `diff` object.

**Notes:**
- Trivial rewording (singular/plural, punctuation) is ignored; changed numbers are never ignored.
- An empty `data` array means the ticker has no diffed filings in the covered set yet, not an error.
- This endpoint reports factual differences between public SEC filings for research and educational purposes. It is not investment advice.

---

## Earnings analysis reports: what a company actually reported

A quarter's results arrive as a press release, a filing, and a call, none of which is a data structure. The earnings analysis report is the assembled version: one object per fiscal quarter carrying the editorial headline, the KPI highlights that matter for that company with year-over-year deltas, the guidance language as management phrased it, and a summary of the earnings call. It is the readout the SentiSense app itself renders, available as a single call rather than something you reassemble from four endpoints.

**Use cases:**
- Give a research agent the last four quarters of a company in one call, already organized by fiscal period.
- Compare guidance language across quarters to see when the tone changed.
- Read the call summary alongside the reported KPIs instead of parsing a transcript.
- Anchor a beat-or-miss judgement by pairing the headline with consensus EPS from the Calendar.

**Freshness:** a quarter typically appears within 48 hours of the company reporting, and the call summary can arrive after the press-release content for the same quarter. Read `generatedAt` (and `transcriptGeneratedAt`) rather than assuming a fixed lag, and expect a quarter to gain the call summary on a later read.

**Coverage:** the actively curated US equity universe, expanding each earnings season. A ticker with no stored quarter returns a **successful, empty response** (`200` with an empty `data` array), not an error. Use canonical ticker symbols: `GOOGL` (not `GOOG`) and `BRK.B` (not `BRK-B`).

**Free preview:** the latest quarter only, shaped rather than truncated. FREE keys receive the headline and report date in full, up to two marquee KPI cards at their latest value, the section titles of the summary and the call in place of their bodies, and a guidance **direction** in place of the guidance language. PRO keys receive every hydrated quarter in full.

## GET /api/v1/stocks/{ticker}/earnings-summaries

Returns the ticker's stored quarters, newest first.

**Authentication:** PRO required for the full quarter and for history. Free keys receive the shaped latest quarter and `totalCount`.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `ticker` | path | Yes | - | Stock ticker symbol, canonical form (e.g. `AAPL`) |
| `limit` | query | No | 12 | Max quarters returned (1 to 40). Values above 40 are capped at 40. Values below 1 are rejected with `400 invalid_limit`. FREE keys receive one quarter regardless of this value. |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/stocks/AAPL/earnings-summaries?limit=4"
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `isPreview` | boolean | `true` when the caller is on the FREE tier |
| `previewReason` | string | `"PRO_REQUIRED"` or `null` |
| `totalCount` | integer | Preview responses only: total quarters available |
| `data` | array | Quarters, newest first (see below) |

**Quarter entry (PRO):**

| Field | Type | Description |
|-------|------|-------------|
| `fiscalPeriod` | string | Display fiscal period, e.g. `"Q2 FY2026"` |
| `reportDate` | string | Date the results were reported, `YYYY-MM-DD` |
| `headline` | string | One-line editorial summary of the quarter |
| `summaryMd` | string | Markdown body summarizing the reported results |
| `kpiHighlights` | array | `{label, value, yoy}`; `value` and `yoy` are display strings, `yoy` may be absent |
| `guidance` | string | Forward-guidance language as reported; absent when the quarter carries none |
| `hasTranscript` | boolean | `true` when a summary of the earnings call exists for this quarter |
| `transcriptSummaryMd` | string | Markdown body summarizing the call; absent when `hasTranscript` is `false` |
| `transcriptHighlights` | array | Call-specific `{label, value, yoy}` entries; absent when there is no call summary |
| `transcriptGeneratedAt` | integer | Epoch seconds the call summary was generated; absent when there is no call summary |
| `sources` | array | `{title, url}` citations backing the quarter |
| `generatedAt` | integer | Epoch seconds the quarter summary was generated |
| `source` | string | Provenance of the quarter summary: `"press_release"` or `"transcript"` |

**Quarter entry (FREE preview):** `fiscalPeriod`, `reportDate` and `headline` in full, plus `kpiHighlights` as up to two `{label, value}` cards, `kpiHighlightCount` (how many cards the full quarter carries), `summaryTopics` and `transcriptTopics` (section titles only, never body text), `hasTranscript`, `hasGuidance`, `guidanceDirection` (`"RAISED"`, `"CUT"`, `"HELD"`, `"MIXED"`, or `null`), `generatedAt` and `source`. The preview never carries a body, a KPI history, or a guidance figure.

**Example Response (PRO, truncated):**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": [
    {
      "fiscalPeriod": "Q2 FY2026",
      "reportDate": "2026-05-01",
      "headline": "Services revenue set a record and margins expanded",
      "summaryMd": "## Segment performance\n\n- **Services revenue**: $00.0B, up 00%\n- **Product revenue**: $00.0B, flat",
      "kpiHighlights": [
        {"label": "Revenue", "value": "$00.0B", "yoy": "+00% YoY"},
        {"label": "EPS", "value": "$0.00", "yoy": "+00% YoY"}
      ],
      "guidance": "Raised the full-year revenue outlook and reaffirmed the margin range",
      "hasTranscript": true,
      "transcriptSummaryMd": "## Demand\n\n- **Enterprise**: management described bookings as ahead of plan",
      "transcriptGeneratedAt": 1780000000,
      "sources": [
        {"title": "Q2 FY2026 results press release", "url": "https://www.example.com/investor/q2-fy2026"}
      ],
      "generatedAt": 1779990000,
      "source": "press_release"
    }
  ]
}
```

**Notes:**
- Figures in the example above are placeholders. Call the endpoint for real values.
- Absence is explicit: a quarter with no call summary sets `hasTranscript: false` rather than omitting the concept, so a client can say "no call summary yet" instead of rendering nothing.
- `guidance` is prose, not a number. Deriving a direction from it is the FREE preview's job (`guidanceDirection`); PRO callers get the language and can classify it themselves.
- This endpoint summarizes public company disclosures for research and educational purposes. It is not investment advice.

---

## GET /api/v1/earnings/recent

The cross-ticker view: which covered companies reported on or after `today - days`, newest first. Use it to drive a post-earnings sweep ("who reported this week"), then follow up per ticker with the per-quarter analysis above.

**Authentication:** API key required. There is no tier gate on this endpoint; every key receives the full window it asks for.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `days` | query | No | 7 | Look-back window in days (1 to 31). Values above 31 are capped at 31. Values below 1 are rejected with `400 invalid_days`. |
| `limit` | query | No | 50 | Max rows returned (1 to 100). Values above 100 are capped at 100. Values below 1 are rejected with `400 invalid_limit`. |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/earnings/recent?days=7&limit=25"
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `isPreview` | boolean | Always `false` on this endpoint |
| `previewReason` | string | Always `null` on this endpoint |
| `data` | array | Reported quarters, newest first (see below) |

**Row:**

| Field | Type | Description |
|-------|------|-------------|
| `ticker` | string | Canonical ticker that reported |
| `fiscalPeriod` | string | Display fiscal period, e.g. `"Q2 FY2026"` |
| `reportDate` | string | Date the results were reported, `YYYY-MM-DD` |
| `headline` | string | One-line editorial summary of the quarter |
| `hasTranscriptSummary` | boolean | `true` when a summary of the earnings call exists for this quarter |
| `generatedAt` | integer | Epoch seconds of the latest content written for this quarter |

**Notes:**
- The window is bounded by `reportDate`, so a quarter reported inside the window appears even if its call summary lands later.
- An empty `data` array means nobody in the covered set reported in that window, not an error.
- This is the only backward-looking earnings feed. The Calendar API is forward-looking and covers scheduled dates, not results.

---

## Earnings Calendar

The Earnings Calendar answers who reports and when. It is a forward-looking feed of scheduled company earnings, each carrying the report date, session timing (before open or after close), fiscal quarter, whether the company has confirmed the date, and the consensus EPS estimate. Use it to build a pre-earnings watchlist or to tell a research agent when a thesis has an upcoming catalyst. FREE keys see the current week; PRO keys see the full forward window (about 30 days), with identical field richness across tiers.

Two headline query shapes:
- `GET /api/v1/calendar/earnings?week=next` for the companies reporting next week (or `?from=&to=` for a custom window).
- `GET /api/v1/calendar/earnings?ticker=AAPL` for a single name's next report date and consensus EPS.

Full reference: [Calendar API](/docs/api/calendar).

---

## Reported Financials and KPIs

Once a company reports, pull the reported numbers. The Stocks API serves standardized financial-statement data and curated company KPIs.

- **Financial statements:** `GET /api/v1/stocks/fundamentals` (income statement, balance sheet, cash flow), with `GET /api/v1/stocks/fundamentals/current`, `GET /api/v1/stocks/fundamentals/periods`, and `GET /api/v1/stocks/fundamentals/historical/revenue`.
- **Company KPIs:** `GET /api/v1/stocks/{ticker}/kpis` returns curated GAAP and non-GAAP metrics extracted from earnings filings and press releases (for example segment and product revenue lines). KPIs are a **PRO preview**: FREE and unauthenticated callers receive metadata only with an empty `kpis` list; PRO returns the full time series. Enumerate coverage with `GET /api/v1/stocks/with-kpis`.

Full reference: [Stocks API](/docs/api/stocks).

---

## Earnings Insights

With the numbers and the filing changes in hand, the Insights API surfaces the takeaway as AI-generated signals. Alongside insider, institutional, sentiment, and volume signal types, it can carry earnings-driven insight types such as `earnings_pulse`.

**What `earnings_pulse` is:** a short editorial takeaway on a quarter a company has already reported, in the standard insight shape (`insightText`, `category`, `confidence`, `urgency`, `generatedAt`). It is a signal, not a report.

**Treat it as opportunistic, not guaranteed.** Insights of this kind are editorial and time-boxed: they surface around an earnings event while the read is fresh, then expire. Outside those windows a ticker can legitimately return no `earnings_pulse` rows at all, and there is no promise of one per quarter, per ticker, or per season. Build for the empty case, and use the per-quarter analysis report for the parts of a quarter you need on every call.

**What it is not:** it is not the per-quarter earnings digest. For the headline, KPI cards with year-over-year deltas, guidance language, and the summary of the earnings call, use the earnings analysis report above (`GET /api/v1/stocks/{ticker}/earnings-summaries`). Pair it with consensus EPS from the Calendar for the beat-or-miss anchor, standardized statements from `GET /api/v1/stocks/fundamentals`, and curated metrics from `GET /api/v1/stocks/{ticker}/kpis`.

Discover which types have data for a ticker with `GET /api/v1/insights/stock/{ticker}/types`, then filter the main feed by `insightType`. Every type on that list has at least one currently servable insight, so `earnings_pulse` missing from it means there is nothing live for that ticker right now.

Full reference: [Insights API](/docs/api/insights).
