Filtering and projection
By default a request returns every column of every row that the endpoint and your entitlement permit, in whatever order the engine chooses. Three query parameters let you narrow the result set:
columns— Projection. Comma-separated list of column names to include in the response. Returns only those columns.sort— Ordering. Column name optionally prefixed with+(ascending, default) or-(descending). Multiple sort fields may be separated by commas.- Pascal-case column names — Filtering. Any column name passed as a query parameter (e.g.
Ticker=AAPL,TradeDate=2023-01-17) is treated as a row-level filter.
The third mechanism is the principal source of confusion when reading
the OpenAPI spec, which lists only the standard parameters
(sort, columns, offset, limit,
response_format, plus a few endpoint-specific ones such as
adjusted and aggregation_logic). Column-name filters
are accepted by the engine but are not enumerated per-endpoint. The
schema for a given dataset is reachable via
GET /api/v1/meta/datasets/{dataset_id}/columns; that
endpoint is your authoritative source for the legal filter set.
The {dataset_id} placeholder takes the opaque catalog id
(see the catalog chapter).
Projection: columns
The default response includes every column. For a wide dataset (the
Trade-and-Quote tables can have 30+ columns) this is wasteful when
you only need a few. The columns parameter solves that.
curl -s -H "X-API-KEY: $ALGOSEEK_API_KEY" \
"https://dev-datasets-api.algoseek.com/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL?adjusted=true&limit=3&columns=TradeDate,EventDateTime,Ticker,Price,Quantity"
The response now contains only those columns:
{
"data": [
{
"TradeDate": "2023-01-17",
"EventDateTime": "2023-01-17T19:59:59.054144-05:00",
"Ticker": "AAPL",
"Price": 133.3122,
"Quantity": 5
},
{
"TradeDate": "2023-01-17",
"EventDateTime": "2023-01-17T19:59:57.718214-05:00",
"Ticker": "AAPL",
"Price": 133.3122,
"Quantity": 1
},
{
"TradeDate": "2023-01-17",
"EventDateTime": "2023-01-17T19:59:57.361405-05:00",
"Ticker": "AAPL",
"Price": 133.3713,
"Quantity": 1
}
],
"pagination": {
"offset": 0,
"limit": 3,
"next_offset": 3
}
}
Projection is the cheapest cost optimisation on the wire side: it
reduces data_returned (the byte count that maps to
account-level bandwidth quota) but does not reduce
data_scanned (which is a function of how much the engine
has to read to evaluate the row predicate). For scan reduction, push
filters into TradeDate-narrowed ranges and per-ticker queries,
covered below.
Ordering: sort
Pass the name of a column with no prefix or a + prefix to sort
ascending; pass it with a - prefix to sort descending.
curl -s -H "X-API-KEY: $ALGOSEEK_API_KEY" \
"https://dev-datasets-api.algoseek.com/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL?adjusted=true&limit=3&sort=-EventDateTime"
Multiple sort fields are comma-separated; later fields break ties on earlier ones:
curl -s -H "X-API-KEY: $ALGOSEEK_API_KEY" \
"https://dev-datasets-api.algoseek.com/api/v1/data/us-equity/eq-trades/2023-01-17/AAPL?adjusted=true&limit=3&sort=-Price,-Quantity"
Pagination (limit/offset) on top of an unspecified
sort is a footgun: if the engine's default order ever changes between
pages, you can skip or repeat rows on page boundaries. For any walk
that issues more than one page, always pass an explicit sort=
on a stable monotonic column (typically EventDateTime for
tick data, TradeDate for daily data, EffectiveDate
for reference data).
Filtering: column names as query parameters
This is the API's most important convention and the one most likely to surprise you: any column on the dataset can be passed as a query parameter to filter rows by that column. The parameter name must match the column name exactly (Pascal case as it appears in the schema) and the value matches by equality.
curl -s -H "X-API-KEY: $ALGOSEEK_API_KEY" \
"https://dev-datasets-api.algoseek.com/api/v1/data/us-equity-ref/eq-shares-outst-basic?Ticker=AAPL&limit=5"
:::caution Gotcha
The shares-outstanding example above requires the Shares
Outstanding entitlement. The dev key used to capture other examples
in this guide is not entitled to it, so the live response is
403 with body
{"detail":"The account is not authorized to access the dataset US Equities Basic Shares Outstanding"}.
The captured sample below is from a separately-entitled environment and
is shown for shape only. Datasets confirmed working with the dev key include
eq-trades (with adjusted=true,
i.e. eq_trades_adj), eq-trades-1min,
eq-market-holidays, eq-ipo, and
eq-adj-factors-basic; substitute one of those if you are
reproducing on the dev key.
:::
{
"detail": "The account is not authorized to access the dataset US Equities Basic Shares Outstanding"
}
Discovering the legal filter set.
Because filter names are column names, you discover them via the catalog endpoint (see the catalog chapter):
curl -s -H "X-API-KEY: $ALGOSEEK_API_KEY" \
"https://dev-datasets-api.algoseek.com/api/v1/meta/datasets/US6014/columns"
[
{ "name": "TradeDate", "data_type": "date", "description": "The trading day" },
{ "name": "BarDateTime", "data_type": "date-time", "description": "The timestamp of the bar start (CST)" },
{ "name": "Ticker", "data_type": "string", "description": "Contract name" },
{ "name": "BaseSymbol", "data_type": "string", "description": "Base product name" },
{ "name": "OpenPrice", "data_type": "number", "description": "Price of the first trade" },
{ "name": "HighPrice", "data_type": "number", "description": "Trade with the highest price" },
{ "name": "LowPrice", "data_type": "number", "description": "Trade with the lowest price" },
{ "name": "ClosePrice", "data_type": "number", "description": "Price of the last trade" },
{ "name": "VolumeWeightPrice", "data_type": "number", "description": "Volume-weighted average price" },
{ "name": "TotalQuantity", "data_type": "integer", "description": "Total number of shares traded" },
{ "name": "BuyAggressorQuantity", "data_type": "integer", "description": "The number of shares traded with \"Aggressor on Buy\"" },
{ "name": "SellAggressorQuantity", "data_type": "integer", "description": "The number of shares traded with \"Aggressor on Buy\"" },
{ "name": "TotalTrades", "data_type": "integer", "description": "Total number of trades" },
{ "name": "BuyAggressorTrades", "data_type": "integer", "description": "The number of \"Aggressor on Buy\" trades" },
{ "name": "SellAggressorTrades", "data_type": "integer", "description": "The number of \"Aggressor on Sell\" trades" }
]
:::caution Gotcha
The column-name filter convention is not listed in the
endpoint's OpenAPI parameters. If you read the spec literally, you
would conclude that the only legal query parameters are
sort, columns, offset, limit, and
response_format (plus a few endpoint-specific ones). You
would also conclude that requests without filters always succeed.
Neither is true: many query-style data endpoints require at
least Ticker, and any column on the dataset can be passed
as a filter. Use the columns endpoint above to discover the legal set
per dataset; do not trust the OpenAPI spec on this point.
:::
Path parameters vs. query filters
The data endpoints come in two URL shapes. Some take key identifiers as path parameters; others take them as query parameters in the column-name convention.
- Path-style — e.g.
GET /api/v1/data/us-equity/eq-trades/{trade_date}/{ticker}. Trade date and ticker are baked into the URL path itself. You cannot pass them as query parameters — the path is what selects the slice. - Query-style — e.g.
GET /api/v1/data/us-equity/eq-trades-1min. Trade date and ticker are passed as query parameters using the column-name convention (TradeDate=2023-01-17,Ticker=AAPL).
The two shapes are functionally equivalent for the engine; the path
shape is a courtesy convenience for endpoints whose
TradeDate+Ticker pair is the natural key. Internal
routing maps the path-style URLs onto the same query path used by the
query-style endpoints, so the same filter, projection, sort, and
pagination semantics apply.
Putting it all together
A realistic, well-shaped query touches all three mechanisms:
curl -s -H "X-API-KEY: $ALGOSEEK_API_KEY" \
"https://dev-datasets-api.algoseek.com/api/v1/data/us-equity/eq-trades-1min?Ticker=AAPL&TradeDate=2023-01-17&adjusted=true&columns=TradeDate,BarDateTime,Ticker,FirstTradePrice,LastTradePrice,Volume&sort=BarDateTime&limit=1000&offset=0"
In Python:
import os, requests
API_KEY = os.environ["ALGOSEEK_API_KEY"]
url = ("https://dev-datasets-api.algoseek.com"
"/api/v1/data/us-equity/eq-trades-1min")
params = {
"Ticker": "AAPL",
"TradeDate": "2023-01-17",
"adjusted": "true",
"columns": "TradeDate,BarDateTime,Ticker,FirstTradePrice,LastTradePrice,Volume",
"sort": "BarDateTime",
"limit": 1000,
"offset": 0,
}
resp = requests.get(url, headers={"X-API-KEY": API_KEY},
params=params, timeout=60)
resp.raise_for_status()
print(resp.json()["pagination"])
The above is also the template most amenable to caching: a stable
URL+param string maps cleanly to a cache key, and the engine output
for a (TradeDate, Ticker, columns, sort) tuple is
deterministic. If you build a per-pipeline disk cache, key it on the
exact param string after lexicographic sort to maximise hit rate
across runs.