# GET /api/v1/lookthrough?portfolio={portfolio}

One endpoint of the TickerInside API, with data through 2026-10-16. Contents of the reference, each section and endpoint as a file: https://tickerinside.com/api/sections/index.md. The whole reference as Markdown: https://tickerinside.com/api/index.md

`GET /lookthrough?portfolio={portfolio}`: the companies under a portfolio, each fund with its weight or amount after a colon, or none for equal weights, as the MCP tool get_etf_portfolio_lookthrough gives them; `top` and `currency` too. CSV: /lookthrough.csv. https://tickerinside.com/api/v1/lookthrough?portfolio=VOO:60,QQQ:40

## Response

The companies a portfolio holds underneath, from portfolio, its funds separated by commas, each with its weight or amount after a colon (VOO:60,QQQ:40 or VOO:40000,QQQ:25000), or none for equal weights. Computed with the code of the MCP tool get_etf_portfolio_lookthrough: each company's weight, its value in the unit of the amounts, and the funds it comes through. top (1 to 200, 25 by default) says how many companies; currency, three letters, is echoed and never converted. A fund renamed is read under its new ticker, which renamed gives. format=csv, or /api/v1/lookthrough.csv, gives one row per company. 1 to 6 funds, whose files weigh at most 30 KB, a file of the other layers a third of its size, and hold at most 1,100 lines between them.

```json
{
  "…": "2 more fields",
  "priced": true,
  "…": "3 more fields",
  "funds": 2,
  "distinct_companies": 518,
  "top_10_weight_pct": 41.1,
  "…": "1 more field",
  "holdings_as_of": {"VOO": "2026-08-31", "QQQ": "2026-10-08"},
  "…": "1 more field",
  "companies": [{"ticker": "NVDA", "weight_pct": 8.189, "weight_pct_2dp": 8.19, "through": [{"fund": "VOO", "weight_pct": 4.8556}, {"fund": "QQQ", "weight_pct": 3.3337}], "value": 8.19}, "… 2 more"],
  "…": "5 more fields"
}
```

- `page_url` (string or null): The web page whose HTML, as the server sends it, prints the answer's figure, so that it reads without JavaScript: for a pair, its written comparison when there is one, else its "Does it diversify me?" answer within that answer's limits; for three funds or more, the x-ray the site wrote of the same funds; for a look-through, the x-ray the site wrote of the portfolio at the same weights (listed under pages in /og/answers.json), or for one fund, its page. Null where no page prints the figure yet: any other overlap of three funds or more or look-through of two funds or more, a pair past those limits, a pair of bond funds.
- `share_url` (string): The address whose HTML reproduces the whole answer on the site: for a pair, its "Does it diversify me?" answer within that answer's limits; for three funds or more and for a portfolio, the x-ray the site wrote of the same funds (listed under pages in /og/answers.json), each weight in percent to 0.01 point and never an amount, in the order of the funds the site wrote it in. Absent where no page prints the answer.
- `priced` (boolean): true when the portfolio gives each fund a weight or an amount; false when every fund counts equally.
- `portfolio_value` (number or null): The sum of the weights or amounts of the funds looked through: the funds under not_looked_through and skipped are left out of it, as they are left out of the percentages. Null when none is given.
- `currency` (string or null): The currency given, upper case, echoed and never converted; unstated when amounts are given without one. Null when none is given.
- `prices_as_of` (string or null): The price date of the figures read from weekly returns. Null when no fund has prices.
- `funds` (integer): How many funds are looked through.
- `distinct_companies` (integer): How many distinct holdings they hold between them, counted by ticker: two share classes of one company (GOOGL and GOOG) count as two.
- `top_10_weight_pct` (number): The weight of the ten largest companies, in percent of what is looked through, summed unrounded and rounded once.
- `looked_through_pct` (number): The part of the portfolio its covered funds make up that the funds looked through are, in percent, by amount or in equal parts: weight_pct and top_10_weight_pct are of that part, and not_looked_through names the rest.
- `holdings_as_of` (object): Each fund's holdings date, by ticker: the date of its issuer file, or the quarter end its SEC filing describes.
- `holdings_source` (object): Each fund's source, by ticker: issuer file, SEC Form N-PORT, trust's own SEC filing, sponsor's own holdings file, or prospectus, no holdings yet.
- `companies` (array of object): The companies underneath, largest first, top of them (25 when top is left out).
- `same_ticker_two_companies` (object): The tickers listed twice: once for the US company of that ticker, once, marked listed_abroad, for the foreign company whose local code it is in another fund, with a note. Absent when there is none.
- `skipped` (object): The tickers not covered, under not_covered, with what is covered (covered_issuers, also_covered and hint). Absent when every ticker is covered.
- `not_looked_through` (array of object): The funds left out of the percentages and the value, each with why and fund_file.
- `covered` (boolean): true when the funds are covered but the answer has no figures (see comparable or computed).
- `computed` (boolean): false when none of the funds holds shares that can be looked through (see reason).
- `reason` (string): Why nothing is computed, when computed is false.
- `renamed` (object): Each ticker asked that a fund had before it was renamed, with its ticker now, under which the answer reads and names it. Absent when there is none.
- `source` (object): The files the answer is computed from: each fund's page_url, null without a page, api_url, holdings_source and, for a fund from a filing, filing_url; benchmark_url, SPY's file, when a one-year beta is computed; license; and cite_as, the line to print under a figure.
- `note` (string): Measurement, not investment advice.
- `license` (string): The licence the data is published under.
- `attribution` (string): How to credit the data: a link to the page of a fund the figure comes from, or to this address, where the medium allows one, the name where it does not.
- `docs` (string): The reference of this endpoint.

A company, in companies:

- `ticker` (string): The company's key, as the funds' holdings write it.
- `weight_pct` (number): Its weight, in percent of what is looked through.
- `weight_pct_2dp` (number): Its weight to two decimals, rounded once from the unrounded sum, as the x-ray page prints it.
- `through` (array of object): Each fund it comes through, the largest first, with its part in percent of what is looked through.
- `value` (number or null): Its value, in the unit of the weights or amounts given. Null when none is given.
- `listed_abroad` (boolean): true for a foreign company's line whose local code is a US ticker too. Absent otherwise.

The analytics record its tickers, never a weight or an amount. The answer, which repeats them, is kept in the edge cache for up to a day under its query, and served only to the same query.

## Errors and redirects

| Status | reason | Meaning | Next request |
|---|---|---|---|
| 200 |  | The file. | Read it. Every file carries its dates. |
| 204 |  | A browser's CORS preflight, an `OPTIONS` request, answered before any redirect: GET and HEAD from any origin, with the headers asked for, kept up to a day. | Nothing to do. |
| 301 |  | An upper case ticker, a share class written `BRK-B` or `BRK/B` (the file is `brk.b.json`), an address without `.json`, `/api/v1` alone, or punctuation copied from a sentence at its end. A key listed abroad with a hyphen, such as `SQM-B`, keeps it. A written comparison asked for in the other order leads to its file: `vym-vs-vig` to `vig-vs-vym.json`. A fund with no file under `/etf/` leads to its file under `/fund/`: `etf/voo.json` to `fund/voo.json`. `/stock/`, the name of the pages, leads to the stock files under `/sec/`: `stock/nvda.json` to `sec/nvda.json`. | Follow it (`curl -L`). `Location` gives the address. |
| 304 |  | Your `If-None-Match` matches the file's `ETag`. | Keep your copy. |
| 400 |  | A computed answer refused its query: `reason` (`missing_parameter`, `unknown_parameter`, `repeated_parameter`, `invalid_value`, `too_few_funds`, `too_many_funds`) and `parameter` say why. | Fix it as `message` says. |
| 400 | `too_large` | Past the limits of one call (fund files read, holdings compared or looked through): `limit` and `asked` give both figures. | Follow the address or tool `message` names first (`answered_by` gives them as fields), or ask for fewer funds per call. |
| 404 | `no_such_endpoint` | No endpoint at this address. | `covered`: `index.json`. |
| 404 |  | Under `/overlap`, `/lookthrough` and `/diversify`: a fund the answer needs is not covered; `not_covered` lists the tickers and `reasons` their codes. | `covered`: `index.json`. |
| 405 |  | A computed answer asked with another method than GET or HEAD (`method_not_allowed`). | Use GET. |
| 503 |  | The file could not be served just then. The body's `error` is `unavailable`, with `Retry-After: 60`. | Retry after a minute. `uptime`: `uptime.json` says whether the site fails its own checks. |

Every 404 body is JSON. It holds `error`, always `not_covered`; `reason`, a code /contract/ lists; `ticker`, as asked for, or null when the address names no ticker; `message`; `docs`; and the follow-up address named above. Under /history/, it also holds `date` when a date was asked for. `before_history`, for a date before a fund's first file, is answered only once holdings at a date are served. A 400 body holds `error` (`bad_request`), `reason`, `message`, `docs`, and `parameter`, or `limit` and `asked`.
