Model or dataset
massive-com/client-python avatar
massive-com/client-python

Massive Python client: REST and WebSocket market data with pagination you control

The official Python client library for the Massive.com REST and WebSocket API.

1,523 stars364 forksPythonMIT

At a glance

What is it?
client-python is the official Python client for the Massive REST and WebSocket API, with a method per endpoint, filter operators on query parameters and automatic pagination that you can turn off. The package was renamed from polygon to massive during the 2025 rebrand, and the older api.polygon.io host keeps working for an extended period.
Who is it for?
Adopt the Massive Python client if you are pulling market data from Massive and want typed method calls, filter operators and sane pagination instead of hand written requests. Do not adopt it for anything outside the Massive API, since it is a thin client for one service and one rebrand.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 6, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • massive-com/client-python1,523 ★ · +0
Star history
Repository2026-10-162026-11-06
massive-com/client-python1.5k1.5k

0 Stars in the last 21 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The problem: a market data API that expects more than requests.get

Financial market data APIs have a shape that generic HTTP clients handle badly. The endpoints are numerous, each with its own required arguments and its own filter parameters. Results are paginated in a way that is easy to misunderstand, and getting that wrong is how a backtest quietly analyses half the data it thinks it has. Authentication is a key in a header, and the same key decides what you are entitled to see.

client-python is the official Python client library for the Massive REST and WebSocket API, and the repository topics describe the domain it serves: realtime stocks, stock data, stock prices, stocks api, trading and websocket.

The value it adds is not exotic. It is that each endpoint becomes a named method with named arguments, so the argument names match the API documentation, and the filter syntax is spelled out in the client rather than left to string concatenation.

The audience is a Python developer working with market data: someone building a data pipeline, a backtest harness or a price monitoring service. The dependency list is correspondingly narrow. The project is built with poetry, requires Python 3.9 or higher, and its runtime dependencies are urllib3 for HTTP, websockets for the streaming side and certifi for certificates. There is no pandas, no numpy and no data frame machinery, which is a deliberate choice: the client returns the API's own objects rather than taking over your memory layout.

The licensing is MIT, the code sits in the massive/ package, and the documentation is published separately at the vendor site.

The rebrand: the package is massive, not polygon

If you have seen this library before, it was called something else, and the change is worth understanding because it touches your dependency file, your import statements and your base URL.

The documentation states that Polygon.io rebranded as Massive.com on Oct 30, 2025. Existing API keys, accounts and integrations continue to work exactly as before. The only change in this SDK is that it now defaults to the new API base at api.massive.com, while api.polygon.io remains supported for an extended period.

That is a careful migration. The keys do not change, the accounts do not change, and the old host does not disappear immediately, so an upgrade does not require a coordinated change across your fleet. The Python side changes more visibly: the distribution is now published as massive, and the import is:

python
from massive import RESTClient

So a code change from polygon to massive is mechanical, but it is a code change, and a requirements file that pins the old distribution will keep resolving to the old client while your new code expects the new one.

The repository reflects the transition too. The package metadata declares the name as massive, describes it as the official Massive, formerly Polygon.io, REST and Websocket client, and the project keeps a .massive/ directory at the root, which holds the machine readable API specifications the client is generated against.

The REST client: one method per endpoint, filters as arguments

The client is constructed with your key and then used through named methods:

python
client = RESTClient(api_key="<API_KEY>")

The endpoints follow the market data model. client.list_aggs walks aggregate bars, with a ticker, a multiplier, a timespan, a from_ and to range and a limit, and it returns an iterable you can loop over. client.get_last_trade and client.get_last_quote return a single current object, while client.list_trades and client.list_quotes return iterables of historical prints for a given ticker and timestamp.

The filter parameters are the part that makes the client more than a thin wrapper. Many of the APIs support additional filters to refine a query, and the documentation lists the four operators: .gt for greater than, .gte for greater than or equal to, .lt for less than, and .lte for less than or equal to. They are applied through a params dictionary, as in the options chain example, where an expiry date and a strike price range are constrained:

python
options_chain = []
for o in client.list_snapshot_options_chain(
    "HCP",
    params={
        "expiration_date.gte": "2024-03-16",
        "strike_price.gte": 29,
        "strike_price.lte": 30,
    },
):
    options_chain.append(o)

The client does not validate the filter names against a schema, it passes them through. If you write expiration_date.gtq, you will get whatever the API says about that parameter, which is a good reason to check the endpoint documentation for the supported filters rather than to guess.

Pagination: limit is a page size, and the client hides the rest

This is the behaviour most likely to cost you an afternoon, and the documentation treats it as the key thing to understand.

By default the client paginates results for endpoints like list_trades and list_quotes behind the scenes. With pagination enabled, the limit parameter controls the page size rather than the total number of results, and the client fetches all pages automatically, yielding results until none remain. So a call with limit=100 returns every trade for that ticker and date, one hundred at a time.

If you want a fixed number of results and want to stop, you disable pagination:

python
client = RESTClient(api_key="<API_KEY>", pagination=False)
trades = [t for t in client.list_trades(ticker="TSLA", limit=100)]

With pagination off, that call returns at most one hundred trades in total and makes no further requests.

The performance tip in the documentation follows from this: if you are fetching large datasets, always use the maximum supported limit for the endpoint, because that reduces the number of API calls. Which is another way of saying that the default page size is probably not what you want for a bulk download.

For a reader deciding whether to adopt the client, this is a fair summary of the trade. The default is convenient and hides a footgun, and it is also a surprise, because the same keyword means different things depending on a constructor argument set three lines earlier.

Debugging: trace and verbose print the request and response

When a request behaves unexpectedly, the client can show you what actually went over the wire. The RESTClient accepts a trace option, and the documentation is explicit that you also need verbose=True to have the trace logged, or your own logger configured:

python
client = RESTClient(trace=True, verbose=True)

With that enabled, the client prints the request URL, the headers sent in the request, and the headers received in the response, for each API request. The example in the documentation shows the shape of the output for a request for TSLA data for a given date, with the request URL rendered as a full path including the ticker, the interval and the date range and the limit.

Two details are worth noting. The output is printed rather than returned, so it goes to standard output, which is what makes it awkward to capture in a structured log unless you have your own logger set up. And it is per request, so a paginated call over thousands of records produces thousands of traces, which is exactly what you want when debugging a single call and exactly what you do not want left on in production.

This is a small feature, and it is the kind of small feature that saves an afternoon.

The build: poetry, black, mypy, and a client generated from the API spec

The Makefile shows how the project is maintained, and the answer is that the client is generated from the vendor's own API specification.

There is a target that updates the REST specification, which runs a Python script kept in the .massive directory, and another that updates the WebSocket specification, which is a single curl of the published JSON document:

bash
	poetry run python .massive/rest.py
bash
	curl https://api.massive.com/specs/websocket.json > .massive/websocket.json

So the endpoint surface of the client tracks the API's own specification rather than being hand maintained, which is why a new endpoint or a changed filter shows up in the library without anyone typing out a method signature by hand.

The quality tooling is also spelled out. The style target runs black over the massive package, the test directories and the examples, and the static target runs mypy over the same three paths, and lint runs both. The tests are split by transport, with separate unittest discovery for the REST and WebSocket suites:

bash
	poetry run python -m unittest discover -s test_rest

The development dependencies explain how the tests run without hitting the live API: pook is a mock library for HTTP, orjson is there for fast serialisation, and the documentation stack is Sphinx with the readthedocs theme and autodoc type hints, which matches the .readthedocs.yml in the repository root.

The repository also carries an AGENTS.md file, and the examples directory is organised into rest/, websocket/, tools/ and launchpad/ subdirectories, so the sample code is split by transport rather than dumped in one folder.

Licence, releases, rate limits and the AI tooling story

The licence is MIT, and the package metadata declares it, so embedding the client in a commercial product carries no copyleft obligation. The release history is active and regular: v2.8.0 on 2026-05-26, v2.7.0 on 2026-05-04 and v2.6.0 on 2026-04-28, and the repository is not archived with the last push on 2026-10-16. The metadata version field reads 0.0.0 because the release version is applied by the release tooling rather than committed in the file, which is a poetry convention rather than a bug.

The constraint to plan around is the API, not the client. The free tier comes with usage limitations that can lead to rate limit errors when they are exceeded, and the documentation points to the subscription plans for larger data requirements. Since the default pagination behaviour fetches every page for you, a naive call over a wide date range on a free tier is the most likely way to hit those limits first. That is an argument for setting pagination=False while you work out the shape of the data, and for using the maximum supported limit for bulk pulls.

The project has also made a specific move for AI tooling, which is unusual to see in a vendor SDK. There is a hosted MCP server at mcp.massive.com that an MCP client can connect to, an llms.txt file at massive.com/docs/llms.txt that gives an agent a machine friendly index of the documentation, and a plugin published from the massive-com/ai repository. In Claude Code, that plugin is installed with the marketplace add and plugin install commands, and the point of it is teaching an assistant about hosts, authentication, entitlements and accurate historical data, which are exactly the four things a generated snippet gets wrong.

So the client is well maintained, permissively licensed and actively documented, and the realistic risks are rate limits and the fact that this SDK covers one API and one rebrand.

Editorial conclusion

Adopt the Massive Python client if you are pulling market data from Massive and want typed method calls, filter operators and sane pagination instead of hand written requests. Do not adopt it for anything outside the Massive API, since it is a thin client for one service and one rebrand. Before you build on it, check the rate limits on your plan, because the free tier can return rate limit errors, and read the WebSocket examples rather than assuming the REST behaviour carries over, since the client exposes a separate test_websocket suite and the README excerpt does not describe the streaming API in detail.

Frequently asked questions

How do I install the Massive Python client?

Use pip with pip install -U massive, and make sure your environment has Python 3.9 or higher. The distribution was renamed from polygon to massive when Polygon.io rebranded as Massive.com on Oct 30, 2025, so existing code needs an updated import.

What does the limit parameter do in the Massive client?

With the default pagination=True, the limit parameter sets the page size rather than the total, and the client fetches all pages automatically. Construct the client with pagination=False to return at most that many results in total and make no further requests.

Does the Massive client still work with the Polygon.io API host?

Yes. The SDK now defaults to the api.massive.com base, and api.polygon.io remains supported for an extended period. Existing API keys, accounts and integrations continue to work exactly as before the rebrand.

How do I see the raw HTTP requests the Massive client makes?

Construct the client with RESTClient(trace=True, verbose=True). It then prints the request URL, the request headers and the response headers for each API request. You need verbose=True, or your own logger configured, for the trace to be emitted.

What licence is the Massive Python client released under?

MIT, declared in the package metadata and the LICENSE file in the repository root, so it can be used inside commercial products without a copyleft obligation.

Official sources

  1. License: MIT
  2. massive-com/client-python on GitHub
  3. Project website
  4. README
  5. Releases

Was this useful?