Chorus.

API

The same data the app shows, as JSON, for your own code. Every cluster with its full context: how long since that filer last bought, how the purchase compares to their usual size, where the stock sits against its range, and what this issuer has done before.

Your keys

Sign in and subscribe to get a key.

Authentication

Send the key as a bearer token. It is never accepted in a query string: URLs end up in access logs, browser history and referer headers, which is the most common way an API credential leaks.

curl -H "Authorization: Bearer ck_your_key_here" \
     https://api.chorusmarket.com/v1/clusters

X-API-Key: ck_... works too if a bearer header is awkward in your client.

Endpoints

PathReturns
GET /v1/clusters Every cluster, newest first. limit (1–200, default 50), offset, and since=YYYY-MM-DD.
GET /v1/clusters/{ticker} Every cluster for one ticker.
GET /v1/issuers/{cik}/history That issuer's reconstructed history, and what the archive covers.
GET /v1/me What your key is, and its rate limit.

A cluster

{
  "object": "list", "count": 126,
  "data": [{
    "ticker": "SCOR",
    "issuer_name": "COMSCORE, INC.",
    "issuer_cik": "1158172",
    "at": "2026-08-27",
    "n_insiders": 2,
    "total_value": 142230,
    "people": [["Kline David", "Director", "https://www.sec.gov/..."],
               ["McLaughlin Matthew F.", "CFO", "https://www.sec.gov/..."]],
    "marks": [[false, false], [false, true]],
    "ctx": ["a CFO and a director",
            "first purchase in 9 months",
            "3.2x typical size",
            "32% below 52-week high"]
  }]
}

ctx is the analysis layer, and the reason the API is not the free feed. marks is one entry per buyer, in the same order as people: [is_entity, has_bought_before]. Every people entry links to the filing on sec.gov, so any number here can be checked against the source.

Rate limits

60 requests a minute per key by default. Every response carries your remaining budget, so a well-written client throttles itself and never sees a refusal.

x-ratelimit-limit: 60
x-ratelimit-remaining: 57
x-ratelimit-reset: 1788191400   unix seconds

Over the limit returns 429 with retry-after. The data changes every six hours, so polling faster than hourly gains you nothing.

Errors

StatusMeans
401 unauthorized No key, an unknown key, a revoked one, or a lapsed subscription. One response for all four, deliberately.
400 bad_requestA parameter was out of range or the wrong shape.
404 not_foundNo such route, or no such ticker.
429 rate_limitedSlow down; retry-after says how long.

There is no CORS header, on purpose. Calling this from a browser would mean shipping your key into a page where anyone can read it.