# GET /api/v1/batch?funds={funds}

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 /batch?funds={funds}`: up to 10 fund files in one answer, keyed by ticker, each as /fund/ answers it, with the tickers not covered and why. https://tickerinside.com/api/v1/batch?funds=VOO,QQQ,VTI

## Response

The files of the funds in funds, a list separated by commas, in one answer keyed by ticker: each exactly what /api/v1/fund/{ticker}.json answers, the answer composed for a fund of another layer included, with the tickers not covered listed with the reason /fund/ gives. 1 to 10 funds. The files of the other layers composed in one call add up to at most 55 KB; the first is always composed.

```json
{
  "asked": ["VOO", "QQQ", "NVDA"],
  "found": 2,
  "not_covered": [{"error": "not_covered", "reason": "has_security_file", "ticker": "NVDA", "…": "1 more field", "security": "https://tickerinside.com/api/v1/sec/nvda.json"}],
  "funds": {"VOO": {"ticker": "VOO", "…": "8 more fields", "holdings_as_of": "2026-08-31", "…": "25 more fields", "holdings": {"NVDA": 8.0927, "AAPL": 7.0432, "…": "1 more"}, "…": "5 more fields"}},
  "…": "3 more fields"
}
```

- `asked` (array of string): The tickers asked for, upper case, each once, in the order asked.
- `found` (integer): How many of them are in funds.
- `not_covered` (array of object): The tickers with no fund file, each with error not_covered, ticker and message: reason has_security_file and security for one with a stock file, else reason no_file and fund, its own address, which gives the specific reason, and covered.
- `not_included` (array of object): Funds of the other layers past what one call composes, each with ticker, fund, its own address, and reason over_budget. Absent when there is none.
- `not_included_note` (string): Why not_included is there.
- `renamed` (object): Each ticker of a fund renamed, with the ticker of the file served under it. Absent when there is none.
- `funds` (object): Each fund found, by ticker as asked: what /api/v1/fund/{ticker}.json answers, a fund file of the stock layers byte for byte, or the answer composed for a fund of another layer.
- `license` (string): The licence the data is published under.
- `attribution` (string): How to credit the data: a link to the page each fund file's cite_as names where the medium allows one, the name where it does not.
- `docs` (string): The reference of this endpoint.

No CSV: each fund's holdings are at /api/v1/fund/{ticker}.csv.

## 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`. |
| 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`.
