Paging through a day of stock trades or quotes from Massive's /v3/trades and /v3/quotes endpoints takes many requests on a busy ticker, because one response holds at most 50,000 rows: AAPL trades for 1 October 2026 came to 707,952 rows, 15 pages at that maximum. Two defaults make a first attempt look like missing data. With no order parameter the rows come back newest first, so the first page starts at the end of the day, just before 20:00 Eastern for AAPL, and with no limit each page holds 1,000 rows.
Applies to
- Plans: stock trades are included in Stocks Developer, Stocks Advanced, Stocks Business and Stocks Business + Expansion. Stock quotes are included in Stocks Advanced, Stocks Business and Stocks Business + Expansion. Stocks Basic and Stocks Starter include neither. The plan tables are on the trades and quotes documentation pages.
- Endpoints: GET /v3/trades/{stockTicker} and GET /v3/quotes/{stockTicker}.
- Asset classes: US stocks. Aggregate bars page differently, which What is the function of the limit parameter in Massive's aggregate endpoint? covers.
How to page through a day of trades or quotes
- Request the day with timestamp=YYYY-MM-DD, order=asc and limit=50000.
- If the response has a next_url, request that URL with your API key added, either as &apiKey=YOUR_API_KEY on the end or in an Authorization: Bearer YOUR_API_KEY header. Change nothing else: the next_url already carries your ticker, date, order and limit.
- Repeat step 2 until a response comes back with no next_url. That response is the last page.
curl -X GET "https://api.massive.com/v3/trades/AAPL?timestamp=2026-10-01&order=asc&limit=50000&apiKey=YOUR_API_KEY"
Response, trimmed to the first of its 50,000 rows, with the cursor shortened:
{
"results": [
{
"conditions": [14, 12, 37, 41],
"exchange": 12,
"id": "1",
"price": 331.99,
"sip_timestamp": 1790841600053889878,
"size": 18
}
],
"status": "OK",
"next_url": "https://api.massive.com/v3/trades/AAPL?cursor=..."
}
The first row's sip_timestamp, 1790841600053889878 nanoseconds since the epoch, is 04:00:00.054 Eastern on 1 October 2026, the day's first trade. The next_url has no apiKey in it, so add yours before you request it.
The same loop in Python, using only the standard library and sending the key in the header from the MASSIVE_API_KEY environment variable:
import json, os, urllib.request
key = os.environ["MASSIVE_API_KEY"]
url = "https://api.massive.com/v3/trades/AAPL?timestamp=2026-10-01&order=asc&limit=50000"
rows, pages = [], 0
while url:
request = urllib.request.Request(url, headers={"Authorization": f"Bearer {key}"})
with urllib.request.urlopen(request) as response:
page = json.load(response)
rows.extend(page["results"])
pages += 1
url = page.get("next_url")
print(pages, len(rows))
Output
15 707952
That is 15 pages and 707,952 rows of AAPL trades for 1 October 2026, and the loop stops on the first response without a next_url. Massive's Python client library does the same for you: by default its list_trades and list_quotes methods fetch every page, and limit sets the page size.
Why the first page looks like the end of the day
The first page of a day of trades or quotes looks like the end of the day when the request has no order parameter, because /v3/trades and /v3/quotes then return the newest rows first:
curl -X GET "https://api.massive.com/v3/trades/AAPL?timestamp=2026-10-01&limit=1&apiKey=YOUR_API_KEY"
Response, trimmed:
{
"results": [
{
"price": 330.7699,
"sip_timestamp": 1790899198178043507,
"size": 2
}
],
"status": "OK"
}
1790899198178043507 is 19:59:58.178 Eastern on 1 October 2026, the newest trade of that day rather than the first. Quotes come back in the same order:
curl -X GET "https://api.massive.com/v3/quotes/AAPL?timestamp=2026-10-01&limit=1&apiKey=YOUR_API_KEY"
Response, trimmed:
{
"results": [
{
"ask_price": 330.8,
"bid_price": 330.75,
"sip_timestamp": 1790899187621062840
}
],
"status": "OK"
}
1790899187621062840 is 19:59:47.621 Eastern on 1 October 2026, the newest quote of that day. Add order=asc to either request to start from the beginning of the day instead.
Page size: 1,000 rows by default, 50,000 at most
The page size on /v3/trades and /v3/quotes is 1,000 rows when the request has no limit, and 50,000 rows at most, as the trades and quotes documentation states. On these two endpoints a larger limit is refused with HTTP 400 rather than reduced:
curl -X GET "https://api.massive.com/v3/trades/AAPL?timestamp=2026-10-01&limit=50001&apiKey=YOUR_API_KEY"
Response, trimmed:
{
"status": "ERROR",
"error": "Failed to parse query parameters from URL: Key: 'TradesQueryParam.Limit' Error:Field validation for 'Limit' failed on the 'max' tag"
}
/v3/quotes returns the same error with QuotesQueryParam.Limit in place of TradesQueryParam.Limit. Use limit=50000 and follow next_url for the rest of the day.
Adding your API key to next_url
A next_url from /v3/trades or /v3/quotes does not include your API key, even when the request that produced it did, so requesting the next_url exactly as returned gets HTTP 401, the same response as this request sent with no key:
curl -X GET "https://api.massive.com/v3/trades/AAPL?timestamp=2026-10-01&limit=1"
Response, trimmed:
{
"status": "ERROR",
"error": "API Key was not provided"
}
Add the key in either of the two ways the REST quickstart documents: append &apiKey=YOUR_API_KEY to the next_url, or send an Authorization: Bearer YOUR_API_KEY header with every request. Either one returns the next page of trades or quotes. Leave the rest of the next_url as it is.
What a date covers
A date in timestamp=YYYY-MM-DD on /v3/trades and /v3/quotes covers that calendar day in Eastern time, midnight to midnight, not the UTC day, so it includes the pre-market and after-hours sessions. On 15 January 2026, when Eastern time was five hours behind UTC, the newest AAPL trade a date query returns falls after midnight UTC:
curl -X GET "https://api.massive.com/v3/trades/AAPL?timestamp=2026-01-15&limit=1&apiKey=YOUR_API_KEY"
Response, trimmed:
{
"results": [
{
"price": 258.29,
"sip_timestamp": 1768525194922196317,
"size": 4
}
],
"status": "OK"
}
1768525194922196317 is 19:59:54.922 Eastern on 15 January 2026, which is 00:59:54 UTC on 16 January. The same request with order=asc starts at 04:00:00.006 Eastern on 15 January, and none of the trades from the evening of 14 January appear. /v3/quotes covers the same Eastern day: for AAPL on 15 January 2026 its newest quote is at 19:59:26 Eastern and its oldest at 03:59:00 Eastern.
For a UTC day or any other window, use timestamp.gte and timestamp.lt with nanosecond timestamps instead of a date. For 15 January 2026 the two windows hold different rows: for F, a UTC midnight-to-midnight range returns 120,526 trade rows starting at 19:00 Eastern on 14 January, against 120,496 for timestamp=2026-01-15.
Splitting a day into windows
Splitting a day of trades or quotes into windows with timestamp.gte and timestamp.lt returns the same rows as paging the whole date. For F on 1 October 2026, the 124,334 trade rows are identical paged ascending, paged descending and paged in 24 one-hour windows bounded by nanosecond timestamps, with no duplicates in any of the three. CROX's 18,766 quotes for the same day match the same way at a page size of 5,000. A window pages with next_url like a whole day: at a page size of 5,000, seven of F's 24 one-hour windows take more than one page, and the 24 windows together return the same 124,334 rows.
If you see an error
{"status":"ERROR","error":"API Key was not provided"} with HTTP 401 on a next_url means the key is missing, because a next_url from /v3/trades or /v3/quotes does not include it. Fix: append &apiKey=YOUR_API_KEY or send Authorization: Bearer YOUR_API_KEY.
Field validation for 'Limit' failed on the 'max' tag with HTTP 400 means limit is above 50,000 on /v3/trades or /v3/quotes. Fix: use limit=50000 and follow next_url.
{"status":"NOT_AUTHORIZED","message":"You are not entitled to this data. Please upgrade your plan at https://massive.com/pricing"} with HTTP 403 is what a Stocks Starter key gets from both endpoints, because Stocks Starter includes neither. Fix: stock trades need Stocks Developer or higher, and stock quotes need Stocks Advanced or a Stocks Business plan. Why am I not authorized (NOT_AUTHORIZED) when calling Massive's REST API or WebSockets? covers the other causes.
A day of trades that appears to start mid-afternoon can be the newest-first default. With no order, the first 50,000 AAPL trades for 1 October 2026 go from 19:59:58 back to 15:50:36 Eastern. Fix: add order=asc and follow next_url until it stops appearing.
A total that changes between identical runs over the same settled day is worth reporting. Start a chat at massive.com/contact with the request URL and the request_id from each page, using the template in How should I go about reporting a possible Massive data discrepancy?.
Related
- What is the function of the limit parameter in Massive's aggregate endpoint?
- Does Massive offer sample code?
- Why am I not authorized (NOT_AUTHORIZED) when calling Massive's REST API or WebSockets?
- Which timestamps are returned for Massive's stock trades and NBBO quotes?
- What timezone are Massive's timestamps in?
- How do Massive's feeds handle canceled trades?
- What is the request limit for Massive's RESTful APIs?

