Response formats: JSON, CSV, and streaming gzip
Every data endpoint can return its rows in one of three shapes, chosen
via the response_format query parameter:
json(default) — The familiar{"data": [...], "pagination": {...}}envelope. Best for small slices and for responses you intend to walk record-by-record in a script.csv— Plain comma-separated text. Best for medium-sized slices that go straight to pandas, R, or a spreadsheet.csv_gzip— CSV compressed with gzip. Best for large result sets that travel over a slow network or that you want to write to disk untouched.
The wire-format choice is also a cost choice: data_returned
in the quota object is byte-counted on the actual bytes sent, which
means gzip-compressed responses consume meaningfully less of your
monthly bandwidth quota than uncompressed equivalents. On TAQ-shaped
payloads, empirically observed compression ratio is roughly
8–10× (~87–90% reduction in data_returned);
see the quotas chapter.
Same data, three formats: a side-by-side comparison
To make the differences concrete, here is the same query — one day of adjusted AAPL trades, limit 5 — in each format. Watch the response size in the per-call meta lines.
JSON
curl -s "https://dev-datasets-api.algoseek.com/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL?adjusted=true&limit=5&response_format=json" \
-H "X-API-KEY: $ALGOSEEK_API_KEY"
{
"data": [
{
"TradeDate": "2023-01-17",
"EventDateTime": "2023-01-17T12:35:55.383637-05:00",
"EventType": "TRADE NB",
"Ticker": "AAPL",
"ASID": 1010000000001033,
"Price": 133.7059,
"Quantity": 100,
"Exchange": "EDGX",
"ConditionCode": 536870945
},
{
"TradeDate": "2023-01-17",
"EventDateTime": "2023-01-17T12:35:55.383868-05:00",
"EventType": "TRADE NB",
"Ticker": "AAPL",
"ASID": 1010000000001033,
"Price": 133.7059,
"Quantity": 100,
"Exchange": "NYSE",
"ConditionCode": 536870945
},
{
"TradeDate": "2023-01-17",
"EventDateTime": "2023-01-17T12:35:55.397113-05:00",
"EventType": "TRADE",
"Ticker": "AAPL",
"ASID": 1010000000001033,
"Price": 133.6986,
"Quantity": 27,
"Exchange": "FINRA",
"ConditionCode": 2147483649
}
],
"pagination": {
"offset": 0,
"limit": 5,
"next_offset": 5
}
}
CSV
curl -s "https://dev-datasets-api.algoseek.com/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL?adjusted=true&limit=5&response_format=csv" \
-H "X-API-KEY: $ALGOSEEK_API_KEY"
"TradeDate","EventDateTime","EventType","Ticker","ASID","Price","Quantity","Exchange","ConditionCode"
"2023-01-17","2023-01-17 04:00:00.005848448","TRADE","AAPL",1010000000001033,132.4067,5,"EDGX",2147484673
"2023-01-17","2023-01-17 04:00:00.006254542","TRADE","AAPL",1010000000001033,132.4067,20,"EDGX",2147484673
"2023-01-17","2023-01-17 04:00:00.007442373","TRADE","AAPL",1010000000001033,132.4067,25,"EDGX",2147484673
"2023-01-17","2023-01-17 04:00:00.007456537","TRADE","AAPL",1010000000001033,132.4067,15,"EDGX",2147484673
"2023-01-17","2023-01-17 04:00:00.007463418","TRADE","AAPL",1010000000001033,132.4067,100,"EDGX",1025
Gzip-compressed CSV
curl -s -O -J \
"https://dev-datasets-api.algoseek.com/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL?adjusted=true&limit=5&response_format=csv_gzip" \
-H "X-API-KEY: $ALGOSEEK_API_KEY"
Content-Type: application/gzip
Content-Length: 228
Connection: keep-alive
Date: Fri, 08 May 2026 20:18:31 GMT
x-pagination-limit: 5
x-amzn-RequestId: f6a8bc92-7768-4515-9c00-2e592b8f8e21
content-disposition: attachment; filename=USEquityMarketData.TradeOnlyAdjusted.csv.gz
x-amzn-Remapped-Connection: keep-alive
x-request-id: 5924b865-9158-4479-a825-d5113b54fde3
x-pagination-next-offset: 5
x-pagination-offset:
x-amz-apigw-id: dD-7sGFMIAMEVhQ=
x-amzn-Remapped-Server: nginx/1.18.0 (Ubuntu)
link: <http://3.89.22.195/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL?adjusted=true&response_format=csv_gzip&offset=5&limit=5>; rel="next"
For programmatic consumers, parse the Content-Disposition
header rather than constructing the filename yourself — the server
encodes the dataset variant, identifier, and date in a stable
convention you can rely on for downstream partitioning.
Reading the gzip body without writing it to disk
For full-day TAQ pulls (tens to hundreds of MB compressed), avoid
loading the entire compressed body into memory. Stream it through
requests.get(stream=True) and feed the chunked stream into
gzip.GzipFile, which itself yields bytes that pandas can
consume incrementally:
import os
import gzip
import pandas as pd
import requests
API_KEY = os.environ["ALGOSEEK_API_KEY"]
URL = ("https://dev-datasets-api.algoseek.com"
"/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL")
def process(chunk: pd.DataFrame) -> None:
"""Replace this with your downstream consumer."""
print(f"got {len(chunk)} rows")
with requests.get(URL,
headers={"X-API-KEY": API_KEY},
params={"adjusted": "true", "limit": 10_000,
"response_format": "csv_gzip"},
stream=True, timeout=300) as resp:
resp.raise_for_status()
# the body is gzip-typed, not gzip-encoded -- do not set Accept-Encoding
with gzip.GzipFile(fileobj=resp.raw) as gz:
for chunk in pd.read_csv(gz, chunksize=10_000):
process(chunk)
The Content-Disposition header is preserved on the response
object (resp.headers["content-disposition"]). Parse it with
the standard library helpers if you need the suggested filename for
downstream partitioning.
When to pick which format
| Use case | Pick |
|---|---|
| Quick exploration in a notebook | json — easiest to inspect with print(json.dumps(...)) |
| Loading a few thousand rows into pandas | csv — pandas reads CSV faster than JSON, and there is no envelope to peel off |
| Backfilling a full historical day or year | csv_gzip — the bandwidth savings dominate |
| Stream-processing without bounded memory | csv_gzip with stream=True |
| Pagination across many pages | json for the first page to read pagination.next_offset, then csv_gzip for the subsequent pages once next_offset is known |
| Saving raw to a partitioned data lake | csv_gzip — store as-is, no re-encoding |
The pagination caveat for CSV.
Because CSV responses do
not embed the JSON envelope, you cannot read
pagination.next_offset from the body. The
Link rel="next" header is also unsafe to follow on this API
(see pitfalls item 2). The robust pattern is therefore:
issue the first call as json to read
pagination.next_offset (and to discover whether you need
pages 2+), then issue subsequent pages as csv_gzip with the
offsets you computed from the JSON walk for the bandwidth saving.
Why not Accept-Encoding: gzip?
HTTP transport-level
content negotiation is not honoured on the deployed API —
neither for CSV nor for JSON responses. Setting
Accept-Encoding: gzip on the request returns the body
uncompressed: Content-Type: text/csv or
application/json, no Content-Encoding: gzip, full
plaintext on the wire. To get a compressed body you must opt in
explicitly with response_format=csv_gzip, which returns
Content-Type: application/gzip and a body whose first two
bytes are the gzip magic 1f 8b. There is no equivalent
explicit-opt-in for JSON — if you want compressed JSON the only
option is to convert to CSV first. Treat
response_format=csv_gzip as the only path to compressed
data; do not rely on the transport layer to negotiate compression
for you.
:::caution Gotcha
The body served under response_format=csv_gzip is
binary-safe gzip. Verify with the magic-byte check
resp.content[:2] == b"\x1f\x8b"
before piping into a gzip decoder, so a misrouted plain-CSV body
fails loudly rather than corrupting the consumer.
:::