---
title: "Shareholders (cap table)"
method: GET
path: "/company/{number}/shareholders"
tags: ["Shareholders"]
---

# Shareholders (cap table)

`GET /company/{number}/shareholders`

## Request

- Base URL: `https://api.companystack.co.uk`
- URL: `https://api.companystack.co.uk/company/{number}/shareholders`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-Api-Key`

The current cap table: every holder by class and across all classes, % of shares and, where every class's voting rights are filed, % of votes, with the date of the shareholder list it comes from and links to the filings. Reconstructed from public filings at Companies House. The company's own register of members is the legal record. Every list is checked against a filed statement of capital: `display` says whether the table may be shown as fact, and `discrepancies` lists where the company's filings disagree. Allottees first seen on a later list are marked inferred in /history. Free keys get the top three holders, the holder count and `top3_pct`; every paid plan (API Starter, Business and Enterprise; web-app Pro and Team) gets everything. Returns 202 `building` while the first reconstruction runs (usually under a minute; companies with long histories take longer): call again after `retry_after_seconds`.

## Path parameters

- `number` string, required

## Response `200`

Cap table

- object
  - `company_number` string
  - `status` 'ready' | 'updating': `updating`: the newest list is in; the history is still being read
  - `notice` string
  - `display` 'fact' | 'flagged' | 'withheld': `fact`: the latest shareholder list adds up to a filed statement of capital and nothing has changed since. `flagged`: shown with `display_reasons`; not to be presented as fact. `withheld`: the holders could not be reconstructed reliably and are not shown
  - `display_reasons` string[]
  - `as_at` string, date, nullable: Date of the shareholder list the table comes from
  - `confirmed_to` string, date, nullable: Latest confirmation statement saying nothing has changed since
  - `built_at` string, date-time
  - `source` object
    - `form` string, nullable
    - `transaction_id` string, nullable
    - `as_at` string, date, nullable
    - `url` string, uri, nullable: The filing on Companies House
  - `total_shares` number
  - `votes_known` boolean
  - `holder_count` integer, nullable
  - `top3_pct` number, nullable: % of all issued shares held by the three largest holders
  - `classes` object[]
    - `class` string
    - `shares` number
    - `pct_of_total` number, nullable
    - `votes_per_share` number, nullable
    - `votes_basis` string, nullable: The words in the filed rights the votes figure rests on
    - `holders` integer, nullable
  - `limited` boolean: true: the top three holders only (free API keys and signed-out website visitors). Every paid plan (API Starter, Business and Enterprise; web-app Pro and Team) gets everything
  - `holders` object[]: All classes, one row per holder, largest first
    - `name` string, nullable: "Name withheld" when the holder has objected to being named
    - `kind` 'individual' | 'corporate'
    - `joint_holders` string[]
    - `name_withheld` boolean
    - `total_shares` number: Shares held across all classes
    - `pct_of_total` number, nullable: % of all issued shares (all classes)
    - `pct_of_votes` number, nullable: % of votes; null unless the voting rights of every class are filed
    - `holdings` object[]
      - `class` string
      - `shares` number
      - `pct_of_class` number, nullable
  - `by_class` object[]: Per class: holders with % of the class
  - `pending` object[]: Shares allotted, cancelled or reduced since the latest list, whose holders the company has not yet filed
  - `discrepancies` object[]
    - `kind` 'reconciliation' | 'filing' | 'movement' | 'parse' | 'identity' | 'gap' | 'coverage'
    - `headline` string
    - `detail` string
    - `as_at` string, nullable
    - `source` object
      - `form` string, nullable
      - `transaction_id` string, nullable
      - `as_at` string, date, nullable
      - `url` string, uri, nullable: The filing on Companies House
  - `discrepancy_count` integer: limited answers: how many places the filings disagree
  - `movement_count` integer: limited answers: holdings that moved between lists in transfers the returns do not itemise (not a disagreement)
  - `build` object
  - `rebuilding` boolean
  - `upgrade_url` string, uri

## Other responses

- `202`: No reconstruction yet: one is being built
- `400`: Invalid company number
- `401`: API key missing, malformed or revoked
- `403`: The key's plan does not include this endpoint (`code: plan_upgrade_required`, with `upgrade_url`), the key may not call it, or the key is beyond the plan's key limit after a downgrade (`code: key_limit_exceeded`: the newest keys are paused until keys are deleted or the plan upgraded)
- `404`: Shareholder information is not available (`code: shareholders_not_available`)
- `429`: Per-minute or per-day limit reached (`code: rate_limited`, `window: minute|day`). Wait `Retry-After` seconds; when both windows are full the day is reported. A refused request does not count against either limit. A bulk lookup (`POST /company/bulk`) counts each company number in it as one request, so one that is more than you have left is refused whole, and the body adds `requested` and `fits`.

---

[API](https://skmtc.dev/companystack/apis/companystack-api.md) · [All operations](https://skmtc.dev/companystack/apis/companystack-api/llms.txt) · [OpenAPI document](https://skmtc.dev/companystack/apis/companystack-api/revisions/8f3234237d2d?raw)
