---
title: "Insider cluster buys (several insiders of one issuer buying together)"
method: GET
path: "/api/news/insider/clusters/"
tags: ["news"]
---

# Insider cluster buys (several insiders of one issuer buying together)

`GET /api/news/insider/clusters/`

Episodes in which **several different insiders of one issuer bought on
the open market together**: an issuer's Form 4 purchase dates are
chained into one episode while consecutive purchases are at most 10
days apart (an episode is cut at 30 days), and every purchase inside
it is examined before a buyer counts.

Counting names is not enough — the loudest look-alikes are an IPO or
PIPE allocation at one price, a mutual-bank conversion, ESPP / DRIP /
director-plan lots, the same transaction reported through two owners
(a director via the fund and the fund itself), and plan lots sitting
next to one real purchase. Each buyer therefore carries a `role`:
`independent` buyers are the cluster; `plan_like`, `unpriced` and
`duplicate_of` buyers are listed so you can see why a 30-name filing
burst is not one. The episode's `pattern` is `open_market` when at
least two independent buyers remain and one of them is an officer or
director, `holders_only` when only 10% holders without a role remain,
and `plan_or_offering` otherwise. The default hides everything but
`open_market`; ask for the rest explicitly. The rule was fixed against
90 episodes checked by hand against the filings (2026-09-22): it shows
58 of 58 real clusters and hides 29 of 30 look-alikes; a 401(k) plan
purchase can still pass, since the filing says so only in a footnote.

`days` is measured on `known_at` — the moment the episode's latest
filing reached EDGAR — so "what became known this month" is one call.
A purchase filed more than ~40 days after the trade is not chained
(2.3% of Form 4 purchases). Coverage starts at `meta.coverage_since`
(the tranche table begins in August 2025); this is a descriptive
screen (`research_only`, not point-in-time), with no returns attached.
Only common-stock purchases outside Rule 10b5-1 plans are considered;
units, preferred and warrants are ignored.

## Query parameters

- `days` integer
- `min_buyers` integer
- `min_usd` integer
- `pattern` 'open_market' | 'plan_or_offering' | 'holders_only' | 'all'
- `symbol` string
- `sort` 'recent' | 'buyers' | 'value'
- `cursor` string
- `page_size` integer

## Response `200`

A page of classified purchase episodes, newest known first by default.

- InsiderClustersPage
  - `results` InsiderCluster[], required
    - `ticker` string, required
    - `name` string, required
    - `cik` integer, required — SEC Central Index Key of the issuer.
    - `window_start` string, date, required — First purchase date of the episode.
    - `window_end` string, date, required — Last purchase date of the episode.
    - `known_at` string, date-time, required — When the episode's latest filing reached EDGAR — the clock `days` is measured on.
    - `buyers` integer, required — Independent buyers.
    - `buyers_total` integer, required — Every distinct reporting owner after duplicate merging.
    - `officer_director_buyers` integer, required — Independent buyers who are an officer or director.
    - `ten_percent_owner_buyers` integer, required — Independent buyers flagged as 10% owners.
    - `fills` integer, required — Purchase tranches counted (a transaction reported twice is counted once).
    - `filings` integer, required — Distinct Form 4 filings.
    - `total_usd` string, nullable, required — Sum of the counted tranches' values (decimal string); `null` when no tranche carries a price.
    - `value_partial` boolean, required — `true` when at least one counted tranche has no price, so `total_usd` understates the episode.
    - `distinct_dates` integer, required
    - `distinct_prices` integer, required — Distinct prices to the cent across priced tranches.
    - `pattern` 'open_market' | 'plan_or_offering' | 'holders_only', required
    - `pattern_reasons` string[], required — Machine-readable notes behind the verdict, e.g. `mass_uniform_date_price`, `same_price_across_dates`, `one_price_multi_date`, `plan_like_buyers`, `unpriced_buyers`, `duplicate_filings`, `no_officer_or_director`.
    - `buyers_detail` ClusterBuyer[], required
      - `name` string, required
      - `title` string, required
      - `is_officer` boolean, required
      - `is_director` boolean, required
      - `is_ten_percent_owner` boolean, required
      - `role` 'independent' | 'plan_like' | 'unpriced' | 'duplicate_of', required — `independent` counts toward the cluster. `plan_like`: the buyer's fills all share an exact date-and-price pair with another buyer's (an allocation, an ESPP/DRIP lot), or match another direct holder's lot at a round price. `unpriced`: no fill carries a price (units, exchanges). `duplicate_of`: the same transaction another reporter already reported; `duplicate_of` names that reporter.
      - `duplicate_of` string, nullable, required
      - `fills` integer, required
      - `usd` string, nullable, required — Sum of this buyer's priced fills (decimal string).
      - `first_date` string, date, required
      - `last_date` string, date, required
      - `news_uids` string[], required — The `uid`s of the insider news rows fronting this buyer's filings — fetch `/api/news/{uid}/` for the event.
    - `filings_detail` ClusterFiling[], required
      - `accession_number` string, required
      - `filed_at` string, date-time, required
      - `sec_url` string, uri, required — The filing's EDGAR index page.
  - `next_cursor` string, nullable, required — Opaque cursor for the next page (pass back with the same `sort`); `null` at the end.
  - `meta` InsiderClustersMeta, required
    - `as_of` string, date-time, required — When the underlying computation ran (the list is refreshed every few minutes).
    - `coverage_since` string, date, nullable, required — Earliest purchase date on record; nothing before it can appear.
    - `episode_gap_days` integer, required
    - `episode_max_days` integer, required
    - `research_only` boolean, required
    - `point_in_time` boolean, required

## Other responses

- `400` — A parameter outside its range or enum
- `401` — Missing or invalid API key.
- `403` — The request reaches past your plan's news-archive horizon (Free 30 days, Basic 90, Pro 180) — either the `cursor` points beyond it, or `from_date` does. The body's `extra` carries `reason: archive_horizon`, your `tier`, the plan's `archive_days`, and (below Pro) an `upgrade` block with the higher tiers' caps and the pricing URL. The window is checked on the FIRST page, unlike the cursor: a `from_date` older than the horizon is refused immediately rather than after paging down to it. A window with only `to_date` is refused when that bound itself is past the horizon (the window is open-ended into the past). Windows and cursors inside the horizon are unaffected, and the request is refused rather than trimmed to the horizon, so a given URL always returns the same body.
- `429` — Rate limit exceeded — either the per-minute burst cap or the per-day volume cap. The `Retry-After` header is the earliest second a retry can succeed, not a guess (a burst block is short, ≤60s; a day-cap block is capped at 3600s — the true reset is `X-RateLimit-Reset`). The `X-RateLimit-*` trio shows the daily volume budget. The body's `extra` names your tier, its `limit_per_minute` / `limit_per_day`, `retry_after_seconds`, and — below Pro — an `upgrade` block with the higher tiers' caps and the pricing URL. A rejected request does not itself consume quota, so retrying after `Retry-After` costs you nothing extra.

## Changes

- **2026-09-23** `18d41c7cf86d` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/alphai/apis/alphai-rest-api/changes/api/news/insider/clusters/get.md)

---

[API](https://skmtc.dev/alphai/apis/alphai-rest-api.md) · [All operations](https://skmtc.dev/alphai/apis/alphai-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/alphai/apis/alphai-rest-api/revisions/44fde16b286e?raw)
