One request to Massive's grouped daily bars endpoint replaces thousands of per-ticker calls, returning a bar for every US ticker that traded on a date. Two defaults decide whether the result is what you wanted: OTC tickers are excluded unless you ask for them, and prices are split-adjusted, which means a permanent record built from the default will change under you the next time a company splits.
Applies to
- Plans: a Stocks subscription. Your tier decides how far back you can request.
- Endpoints: /v2/aggs/grouped/locale/us/market/stocks/{date}, with include_otc to widen it. For bulk history over many dates, the flat files are better still.
- Asset classes: US stocks and ETFs. OTC is excluded unless you pass include_otc=true.
How to get one day for every ticker
curl -X GET "https://api.massive.com/v2/aggs/grouped/locale/us/market/stocks/2026-09-04?adjusted=true&apiKey=YOUR_API_KEY"
Response
{
"queryCount": 12510,
"resultsCount": 12510,
"adjusted": true,
"results": [
{ "T": "NFRA", "v": 32429.9658, "vw": 65.7824, "o": 65.64, "c": 65.73, "h": 65.9428, "l": 65.64, "t": 1788552000000, "n": 278 }
],
"status": "OK"
}
T is the ticker, n is the number of trades and vw is the volume-weighted average price. Volume is often fractional, because fractional shares trade. t is 16:00 Eastern on the session, the close rather than the start, so do not use it as a window boundary.
By default the response excludes OTC tickers: that request returned 12,510 rows, and the same request with &include_otc=true returned 16,442. If your universe is meant to include OTC, ask for it explicitly.
Which tool for which job
Which tool suits the job depends on how many dates you need, because the grouped endpoint covers one date at a time:
| What you need | Use |
|---|---|
| Today's or one day's bar for every ticker | Grouped daily bars, one request |
| A date range for one ticker | /v2/aggs/ticker/{ticker}/range/1/day/{from}/{to} |
| Years of daily bars for every ticker | The flat files. One file per day, downloaded rather than paged |
| The current price for a handful of tickers | /v3/snapshot |
A loop over the grouped endpoint, one call per date, is a reasonable way to backfill a few months. For years of history, the flat files are the intended path and do not consume requests.
Two things to decide before you store it
- Adjusted or not. adjusted=true is the default and returns split-adjusted prices, which change retroactively when a ticker splits. If you are keeping a permanent record, store the unadjusted values with adjusted=false and apply splits yourself, or your history will quietly change under you.
- Weekends and holidays. A non-trading date returns an empty results array with HTTP 200. Check /v1/marketstatus/upcoming rather than treating an empty day as a failure.
If you see an error
An empty results array with "status": "OK" means no trading on that date. It is a weekend, a holiday, or a date before your plan's history window.
{"status":"NOT_AUTHORIZED"} on an older date is your plan's history window rather than missing data.
Fewer rows than you expected is usually the OTC default rather than the date. Add include_otc=true and compare. Beyond that, the ticker universe genuinely changes between dates as companies list, delist and change symbol.

