openapi: 3.1.0
info:
title: alphai REST API
version: "1.24.0"
description: |
Public REST API for alphai's relevance-scored, ticker-linked financial news.
All endpoints accept `Authorization: Bearer ak_live_…` (issued from your
`/account/api-keys`). Authenticated traffic is metered per account with two
layers — a per-minute burst cap and a per-day volume cap (Free 20/min +
100/day, Basic 60/min + 10,000/day, Pro 150/min + 100,000/day); a request
passes only if both are under budget. The Free tier is for evaluation /
personal non-commercial use; Basic is licensed for internal commercial use;
Pro adds redistribution of the enriched feed. Send all API traffic to
`api.alphai.io`; a key is required on every request.
Every keyed response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`
and `X-RateLimit-Reset`; these report the per-day volume layer (Reset =
epoch seconds of the next 00:00 UTC reset) so you can watch your daily budget
without provoking a 429. A per-minute burst surfaces only as a 429 with a
short `Retry-After`. A 429 body also names your tier, its caps and an
`upgrade` block. The headers reflect origin processing, so a response
served from a shared cache may omit them.
News-archive depth is tiered: Free keys can page the feeds back 30 days,
Basic 90 days, Pro 180 days. Paging past your horizon returns `403`
with an `extra.reason` of `archive_horizon` (see the ArchiveGated response).
Coverage note: our collectors expanded in June 2026, so archive months
before 2026-06 hold fewer articles per day than the current feed.
Insider data (SEC EDGAR Form 4) flows through the same news shape:
`category=insider` rows in the feed, a dedicated `/api/news/insider/`
route, and 30-day per-ticker rollups at
`/api/symbols/{ticker}/insider-summary/`. For charts and analysis there
is `/api/symbols/{ticker}/insider-trades/`: the complete per-ticker
event history with 3m/12m/all-time rollups, weekly and monthly dollar
buckets, and every event of the trailing 12 months in one response.
Market-wide macro coverage (central-bank decisions, CPI/jobs prints,
commodities, geopolitics) is in the feed too, under the `macro_economy`,
`commodities` and `geopolitics` categories and a dedicated
`/api/news/macro/` route. Macro rows are market-wide events, so most
carry an empty `tickers` list — filter them by category, not by symbol.
The forward half of the macro loop is `/api/calendar/`: the official
schedule of upcoming US macro releases (FOMC decisions and minutes, CPI,
PPI, jobs report, GDP estimates, PCE, retail sales, jobless claims,
JOLTS), each with a stable occurrence `uid` that survives reschedules.
Ask the calendar what's coming, then read `/api/news/macro/` for what a
release meant once it's out.
Query parameters are validated strictly. An unknown or misspelled
parameter returns 400 naming the field, and the error body carries
`extra.allowed_params` — every parameter that endpoint accepts — so you
never have to guess. Common mix-ups also get a did-you-mean (`limit` and
`per_page` point to `page_size`; `offset`, `page`, `skip` and the
`after_id`/`before_id` family point to `cursor`; `ticker` points to
`symbol`). Parameters that belong to the MCP server rather than to this
API — free-text `q`/`query`/`search`, and `min_actionability` — say so
instead of failing silently.
See https://alphai.io/developers for the score and sentiment legend, and
https://alphai.io/pricing for tier limits.
contact:
name: alphai support
email: support@alphai.io
url: https://alphai.io/contact
license:
name: Proprietary
servers:
- url: https://api.alphai.io
description: Production (API host — key required)
security:
- apiKey: []
tags:
- name: news
description: Relevance-scored, ticker-linked news.
- name: symbols
description: Active equity, crypto, and foreign symbols (tickers).
- name: calendar
description: Scheduled US macro releases (FOMC, CPI, jobs, GDP, PCE…).
paths:
/api/news/:
get:
tags: [news]
summary: List news (cursor-paginated)
description: |
Feed of enriched articles, newest first. Default filter:
`relevance_score >= 4` AND at least one active ticker. Pagination is
cursor-based with a default page size of 10 (any size from 1 to 20 via
`page_size=`; Pro keys go up to 50): omit `cursor` for the newest page,
then pass the
`next_cursor` from each response to fetch the next (older) page.
`next_cursor: null` means the end of the feed. Cursors are opaque — do
not construct or parse them; an invalid cursor returns 400. Archive
depth is tiered: paging back past your plan's horizon (Free 30 days,
Basic 90, Pro 180) returns 403 with an upgrade hint.
**Delta polling** (`sort=ingested`): the same feed ordered by the
moment rows became available, for "what is new since my last poll".
Articles reach the feed later than their publish time (collection
median ~30 min for general news, with a long tail), so a poller that
filters by `time_published` misses most late arrivals; `sort=ingested`
never misses a row. First call without `cursor` returns the newest
`page_size` rows and a cursor at the feed head; each later call with
the previous `next_cursor` returns only rows added since. In this mode
`next_cursor` is always non-null — empty `results` means you are
caught up, keep the cursor and poll again later (responses are cached
for 60 s, so polling more often than once a minute buys nothing). New
rows only: an update to an already-delivered article is not re-sent.
`time_published` is not monotonic within a delta page; sort client-side
if you need chronological order. A cursor is only valid with the sort
mode that issued it.
Delta mode carries live coverage only: when we add history in bulk
(backfilling an earlier period), those rows do NOT enter this stream —
they would arrive as thousands of "new" items that are months old and
push your cursor far behind the live feed. They are served normally in
`sort=published`, by date filters and by `/api/news/{uid}/`, so a
one-off catch-up over the archive is a published-mode query.
**Keeping up.** One call returns at most `page_size` rows, so a poller
holds its position at the head only while `calls per day × page_size`
stays above the daily volume of the stream it asked for. Below that it
falls a little further behind every day, and the symptom misleads:
`time_published` reads hours or days old while the data is current.
What went stale is the cursor, not the feed. So drain instead of
polling once per tick: when a page comes back with `results` filled,
call again immediately, and sleep only once `results` is empty. That
clears a burst within the same cycle and lets a poller catch up by
itself after downtime. Two levers if the call budget is still short,
and they multiply: `page_size` (up to 20, or 50 on a Pro key) and a
narrower stream (`min_relevance`, `symbol`, `category`). For scale, at
the default `>= 4` floor the feed carries roughly 2,700 rows a day,
while `min_relevance=7` carries roughly 1,000.
A poller that never catches up eventually meets the archive gate: the
403 below is keyed on the age of the first row you have not read yet,
so it fires on a delta poller that never paged back at all.
parameters:
- in: query
name: cursor
description: Opaque cursor from a prior response's `next_cursor`. Omit for the newest page.
schema: { type: string }
- in: query
name: symbol
description: >-
Filter to articles that mention this ticker. US equities use the
bare symbol (`NVDA`); cryptocurrencies use the `<SYM>-USD` form
(`BTC-USD`), and a bare crypto name resolves to it (`DOGE` matches
`DOGE-USD`); foreign listings use the Yahoo suffix (`VOD.L`). A
delisted symbol returns its news history. A renamed company's
current ticker also matches articles tagged with its former
ticker, and any share class of an issuer matches articles tagged
with its other listed classes (`GOOGL` includes rows tagged
`GOOG`); article tags stay as published.
schema: { type: string, example: "NVDA" }
- in: query
name: category
description: >-
Keep only these categories. Accepts a single value, a CSV list
(`category=earnings,insider`), or a repeated parameter — matches
any of them (OR).
style: form
explode: true
schema:
type: array
items: { $ref: "#/components/schemas/NewsCategory" }
- in: query
name: exclude_categories
description: >-
Drop these categories from the feed. Same single / CSV / repeated
forms as `category`.
style: form
explode: true
schema:
type: array
items: { $ref: "#/components/schemas/NewsCategory" }
- in: query
name: min_relevance
description: Override the default ≥4 threshold.
schema: { type: integer, minimum: 1, maximum: 10, default: 4 }
- in: query
name: page_size
description: >-
Items per page, default `10`. Any value from `1` to `20` is accepted
on every tier; `21`-`50` requires a Pro key. A value outside `1`-`50`,
or an over-`20` page without a Pro key, returns 400 — the page is
never silently clamped. Pagination is otherwise unchanged: pass each
response's `next_cursor` back as `cursor` regardless of page size.
schema: { type: integer, minimum: 1, maximum: 50, default: 10 }
- in: query
name: collapse
description: >-
`story` collapses coverage of one event to a single representative
row (the story root): syndicated reprints and independently written
articles about the same event, matched on headline and lead
similarity. Populates the `story_id`, `sources_count` and `sources`
fields on each item. Omit for the full feed (every article, story
fields `null`). Only `story` is accepted; any other value returns
400.
Note: row-level filters (`symbol`, `category`, `min_relevance`)
apply to the story's representative root, so a story whose root does
not match the filter is omitted entirely.
schema: { type: string, enum: [story] }
- in: query
name: sort
description: >-
`published` (default) is the reverse-chronological feed.
`ingested` is delta-polling mode: rows in the order they became
available, ascending, with `next_cursor` always returned (empty
`results` = caught up) — see the endpoint description. All other
filters apply unchanged in both modes. Cursors are mode-specific:
a cursor is only valid with the sort mode that issued it (a
mismatch returns 400).
schema: { type: string, enum: [published, ingested], default: published }
responses:
"200":
description: A page of enriched articles.
content:
application/json:
schema: { $ref: "#/components/schemas/NewsPagination" }
"400": { description: Invalid cursor (opaque; reuse `next_cursor`), a cursor replayed into the other `sort` mode, unsupported `collapse`/`sort` value, or a `page_size` outside 1-50 or not permitted on this tier. }
"403": { $ref: "#/components/responses/ArchiveGated" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/news/trending/:
get:
tags: [news]
summary: Trending news (last 48h)
description: >-
Top stories from the trailing 48h: `relevance_score >= 8`, ranked by
relevance score decayed by article age, so a fresh story outranks an
equally-scored stale one. At most two stories per ticker. Fixed size
of 10, no pagination. Coverage of one story, syndicated reprints and
independent write-ups of the same event alike, is collapsed to a
single representative, and each item carries the `story_id`,
`sources_count` and `sources` fields for the story it represents.
Most stories are carried by a single outlet, so `sources_count` is
usually 1; see its field description.
responses:
"200":
description: List of enriched articles.
content:
application/json:
schema:
type: array
items: { $ref: "#/components/schemas/RichNewsArticle" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/news/insider/:
get:
tags: [news]
summary: Insider-transaction news (SEC Form 4)
description: |
Dedicated insider feed (`category=insider`): SEC EDGAR Form 4 insider
activity ONLY — one deterministic-templated row per filing event
(a filing's non-derivative trades of one type and holding form,
aggregated: total shares, volume-weighted average price and executed
range, total value), surfaced shortly after filing, with the relevance
score computed from the event's total (size, buy vs. sell, 10b5-1 plan
or not). Same enriched shape, ticker
and `relevance_score >= 4` filtering, and cursor-based pagination as
`/api/news/`. Equivalent to `/api/news/?category=insider`, surfaced as a
first-class route. For aggregate stats instead of the stream, see
`/api/symbols/{ticker}/insider-summary/`.
To watch for new filings, poll with `sort=ingested` rather than
re-reading the newest page: a Form 4 is filed up to several days after
the trade it reports, so a new event often enters the feed already
below the head of the publish-ordered page. Delta mode orders by the
moment the row became available, so it never misses one. The contract
is identical to `/api/news/?sort=ingested` — see that endpoint for the
full description.
parameters:
- in: query
name: cursor
description: Opaque cursor from a prior response's `next_cursor`. Omit for the newest page.
schema: { type: string }
- in: query
name: symbol
description: >-
Filter to insider news that mentions this ticker. Delisted
symbols return their history; a renamed company's current ticker
also matches rows tagged with its former ticker.
schema: { type: string, example: "NVDA" }
- in: query
name: min_relevance
description: >-
Override the default ≥4 threshold. Insider rows score
deterministically from the event's summed dollar value (plus
buy/10b5-1 modifiers), so this acts as an "only large trades"
dial — e.g. `min_relevance=7` keeps roughly $10M+ events.
schema: { type: integer, minimum: 1, maximum: 10, default: 4 }
- in: query
name: page_size
description: >-
Items per page, default `10`. Any value from `1` to `20` is accepted
on every tier; `21`-`50` requires a Pro key. A value outside `1`-`50`,
or an over-`20` page without a Pro key, returns 400.
schema: { type: integer, minimum: 1, maximum: 50, default: 10 }
- in: query
name: sort
description: >-
`published` (default) is the reverse-chronological feed.
`ingested` is delta-polling mode, with the same contract as on
`/api/news/`: rows in the order they became available, ascending,
`next_cursor` always returned (empty `results` = caught up), and
all other filters applied unchanged. Prefer it for watching insider
activity — a Form 4 is filed days after the trade it reports, so a
new event routinely lands below the newest page of the
publish-ordered feed and a poller reading only the head misses it.
Cursors are mode-specific: a cursor is only valid with the sort mode
that issued it (a mismatch returns 400).
schema: { type: string, enum: [published, ingested], default: published }
responses:
"200":
description: >-
A page of enriched insider-transaction articles. Each item
additionally carries the structured `insider` event block
(side / shares / average price / total value / reporting owner) —
populated on this endpoint only.
content:
application/json:
schema: { $ref: "#/components/schemas/NewsPagination" }
"400": { description: Invalid cursor (opaque; reuse `next_cursor`), a cursor replayed into the other `sort` mode, an unsupported `sort` value, or a `page_size` outside 1-50 or not permitted on this tier. }
"403": { $ref: "#/components/responses/ArchiveGated" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/news/macro/:
get:
tags: [news]
summary: Market-wide macro news (central banks, prints, commodities, geopolitics)
description: |
Dedicated macro feed: the `macro_economy`, `commodities` and
`geopolitics` categories in one stream — central-bank decisions and
statements (FOMC), inflation/jobs prints, oil and gold, geopolitical
risk. Same enriched shape, `relevance_score >= 4` floor and
cursor-based pagination as `/api/news/`; equivalent to
`/api/news/?category=macro_economy,commodities,geopolitics`, surfaced
as a first-class route.
Macro rows are market-wide, so most carry an empty `tickers` list —
that is by design (an FOMC statement is not news about one company),
and the per-article analysis block is still populated. A macro row
that IS about listed companies (an oil-price story tagged to majors)
keeps its tickers.
To watch for new releases, poll with `sort=ingested` — same delta
contract as `/api/news/?sort=ingested`.
parameters:
- in: query
name: cursor
description: Opaque cursor from a prior response's `next_cursor`. Omit for the newest page.
schema: { type: string }
- in: query
name: category
description: >-
Narrow to a subset of the macro categories, comma-separated.
Values outside `macro_economy`/`commodities`/`geopolitics` return
400 (the full category filter lives on `/api/news/`).
schema: { type: string, example: "macro_economy" }
- in: query
name: min_relevance
description: >-
Override the default ≥4 threshold. On release days the release
itself scores 7-9, so `min_relevance=7` keeps roughly
"the events" and drops the commentary.
schema: { type: integer, minimum: 1, maximum: 10, default: 4 }
- in: query
name: page_size
description: >-
Items per page, default `10`. Any value from `1` to `20` is accepted
on every tier; `21`-`50` requires a Pro key. A value outside `1`-`50`,
or an over-`20` page without a Pro key, returns 400.
schema: { type: integer, minimum: 1, maximum: 50, default: 10 }
- in: query
name: sort
description: >-
`published` (default) is the reverse-chronological feed.
`ingested` is delta-polling mode, with the same contract as on
`/api/news/`. Cursors are mode-specific: a cursor is only valid
with the sort mode that issued it (a mismatch returns 400).
schema: { type: string, enum: [published, ingested], default: published }
responses:
"200":
description: A page of enriched macro articles.
content:
application/json:
schema: { $ref: "#/components/schemas/NewsPagination" }
"400": { description: Invalid cursor (opaque; reuse `next_cursor`), a cursor replayed into the other `sort` mode, a category outside the macro set, or a `page_size` outside 1-50 or not permitted on this tier. }
"403": { $ref: "#/components/responses/ArchiveGated" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/calendar/:
get:
tags: [calendar]
summary: Scheduled US macro releases (economic calendar)
description: |
The official forward schedule of US macro releases: FOMC decisions
(with SEP and press-conference markers) and minutes, CPI, PPI, the
jobs report (nonfarm payrolls), GDP estimates (advance/second/third),
PCE, advance retail sales, weekly jobless claims and JOLTS — sourced
from the agencies' own schedule pages (Fed, BLS, BEA, Census, DOL).
Each occurrence carries a stable `uid` (`US-CPI-2026-07`) that
survives reschedules: a moved release keeps its identity, updates
`scheduled_at` and reports `schedule_status`. `phase` says only
whether the scheduled moment has passed (`upcoming`/`elapsed`) — it
deliberately does not claim the agency actually published. Pair the
calendar with `/api/news/macro/` to read what a release meant once
it's out.
The window is `[from_date, to_date)` — from inclusive, to exclusive;
date-only values mean UTC midnight; defaults are today (UTC) → +7
days; the span is capped at 400 days. No pagination: a full year of
every series is ~250 rows (hard cap 500), ordered by `scheduled_at`
ascending. Cancelled and postponed occurrences stay in the response
with their `schedule_status`.
parameters:
- in: query
name: from_date
description: >-
Window start, inclusive. `YYYY-MM-DD` (UTC midnight) or an ISO
datetime (naive = UTC). Default: today, UTC midnight.
schema: { type: string, example: "2026-08-07" }
- in: query
name: to_date
description: >-
Window end, exclusive. Same formats. Default `from_date` + 7 days;
span capped at 400 days.
schema: { type: string, example: "2026-08-14" }
- in: query
name: event_key
description: Narrow to specific series, comma-separated. Unknown keys return 400.
schema: { type: string, example: "cpi,nfp,fomc_decision" }
- in: query
name: importance
description: Narrow by importance tier.
schema: { type: string, enum: [high, medium, low] }
- in: query
name: country
description: v1 covers US releases only.
schema: { type: string, enum: [US], default: US }
responses:
"200":
description: Occurrences within the window, `scheduled_at` ascending.
content:
application/json:
schema: { $ref: "#/components/schemas/CalendarEvents" }
"400":
description: >-
Unknown parameter or value, a malformed date, `to_date` not after
`from_date`, or a window over 400 days.
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/news/{uid}/:
get:
tags: [news]
summary: Get a news article by UID
parameters:
- in: path
name: uid
required: true
schema: { type: string, pattern: "^[a-f0-9]{16}$" }
responses:
"200":
description: A single enriched article.
content:
application/json:
schema: { $ref: "#/components/schemas/RichNewsArticle" }
"404": { $ref: "#/components/responses/NotFound" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/news/{uid}/related/:
get:
tags: [news]
summary: Articles related to one article
description: |
Up to 6 articles related to the given article: fresh articles sharing
a ticker first, then same-category recents as backfill. Same enriched
shape and `relevance_score >= 4` filtering as `/api/news/`; insider
(SEC Form 4) rows are excluded unless the base article is itself
insider. No pagination — the list is a fixed-size block.
parameters:
- in: path
name: uid
required: true
schema: { type: string, pattern: "^[a-f0-9]{16}$" }
responses:
"200":
description: Related enriched articles (possibly fewer than 6).
content:
application/json:
schema:
type: object
required: [results]
properties:
results:
type: array
maxItems: 6
items: { $ref: "#/components/schemas/RichNewsArticle" }
"404": { $ref: "#/components/responses/NotFound" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/symbols/:
get:
tags: [symbols]
summary: List active tickers
description: >-
All active symbols (US equities, crypto, and foreign listings),
alphabetical by ticker. ~10k entries — cache aggressively, or slice with
the optional `limit`/`offset` params (the response stays a bare array
either way). Pass `search` to resolve a name, brand or ticker prefix to
its canonical symbol (`search=bitcoin` returns `BTC-USD`,
`search=spacex` returns `SPCX`).
parameters:
- in: query
name: limit
description: Return at most this many symbols. Omit for the full list.
schema: { type: integer, minimum: 1, maximum: 10000 }
- in: query
name: offset
description: Skip this many symbols from the start of the list.
schema: { type: integer, minimum: 0, default: 0 }
- in: query
name: search
description: >-
Resolve a query to matching symbols: ticker-prefix, company-name
substring, or the company's brand name where that differs from its
registered name (`search=spacex` returns `SPCX`, registered as
SPACE EXPLORATION TECHNOLOGIES CORP). Case-insensitive; exact
ticker, exact name and brand matches rank above prefix and
substring matches. Useful for finding the canonical form of a name
(`search=bitcoin` returns `BTC-USD`).
schema: { type: string, example: "bitcoin" }
responses:
"200":
description: List of active symbols.
content:
application/json:
schema:
type: array
items: { $ref: "#/components/schemas/Symbol" }
"400": { description: Out-of-range or unknown query parameter. }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/symbols/{ticker}/:
get:
tags: [symbols]
summary: Symbol detail
parameters:
- in: path
name: ticker
required: true
description: >-
Ticker symbol. US equities are bare (`AAPL`); cryptocurrencies use
the `<SYM>-USD` form (`BTC-USD`); foreign listings use the Yahoo
suffix (`VOD.L`).
schema: { type: string, pattern: "^[A-Z0-9][A-Z0-9.\\-]{0,19}$", example: "BTC-USD" }
responses:
"200":
description: >-
Symbol with extended metadata. Resolves delisted symbols too:
check `status`, and `renamed_to` for the successor ticker when
the company continues under a new symbol.
content:
application/json:
schema: { $ref: "#/components/schemas/Symbol" }
"404": { $ref: "#/components/responses/NotFound" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/symbols/{ticker}/sentiment-summary/:
get:
tags: [symbols]
summary: 7-day AI sentiment rollup for one ticker
description: |
Counts of bullish / neutral / bearish per-ticker sentiment calls from
the enriched news flow over the trailing 7 days, plus per-day buckets.
Insider (SEC Form 4) template rows are excluded — this reflects press
coverage, not filings.
parameters:
- in: path
name: ticker
required: true
description: >-
Accepts the same ticker forms as the symbol detail endpoint: bare
crypto names resolve to their `<SYM>-USD` listing (`DOGE` →
`DOGE-USD`; the response echoes the resolved ticker), and delisted
or renamed symbols stay addressable.
schema: { type: string, pattern: "^[A-Z0-9][A-Z0-9.\\-]{0,19}$" }
responses:
"200":
description: >-
Sentiment counts for the window. Zeros mean a quiet week for a
real listing; a ticker no symbol owns returns 404 instead.
content:
application/json:
schema: { $ref: "#/components/schemas/TickerSentimentSummary" }
"400": { description: Malformed ticker. }
"404": { $ref: "#/components/responses/NotFound" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/symbols/{ticker}/insider-summary/:
get:
tags: [symbols]
summary: 30-day insider-transaction rollup for one ticker
description: |
Aggregated SEC Form 4 activity over the trailing 30 days: buy/sell
transaction counts, dollar volumes, the share of transactions executed
under pre-arranged 10b5-1 plans, and the most active insiders ranked
by absolute net value (buys minus sells).
parameters:
- in: path
name: ticker
required: true
description: >-
Accepts the same ticker forms as the symbol detail endpoint: bare
crypto names resolve to their `<SYM>-USD` listing, and delisted or
renamed symbols stay addressable. Crypto and foreign listings have
no Form 4 flow, so they return zeros.
schema: { type: string, pattern: "^[A-Z0-9][A-Z0-9.\\-]{0,19}$" }
responses:
"200":
description: >-
Insider activity stats for the window. Zeros mean no filings in
the window for a real listing; a ticker no symbol owns returns
404 instead.
content:
application/json:
schema: { $ref: "#/components/schemas/TickerInsiderSummary" }
"400": { description: Malformed ticker. }
"404": { $ref: "#/components/responses/NotFound" }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/api/symbols/{ticker}/insider-trades/:
get:
tags: [symbols]
summary: Form 4 event history and chart aggregates for one ticker
description: |
The complete per-ticker insider-trading payload behind
alphai.io/stock/{ticker}/insider-trades: the paginated Form 4 event
history plus everything a chart needs, in one request. One event is
a filing's whole tranche group (shares summed, the price
value-weighted, a 10b5-1 ladder is ONE event), same folding as the
feed's `insider` block.
# --- truncated at 32 KB (72 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/alphaai/refs/heads/main/openapi/alphaai-rest-api-openapi.yml