Massive entitles an API key per product, not per account, and that single fact explains almost every not-authorized response. There is no account-wide plan: you hold Stocks, or Options, or Indices, or Currencies, or Futures, each at its own tier, and a request is checked against the one it belongs to. So a fully paid key gets refused the moment the request crosses into a product you did not buy, which is why an ETF such as SPY works while an option on it does not.
Applies to
- Plans: all plans, including the free Basic plan.
- Endpoints or feeds: every REST endpoint under https://api.massive.com, flat-file downloads and the file browser, every WebSocket cluster under wss://socket.massive.com, and the delayed feeds under wss://delayed.massive.com.
- Asset classes: stocks, options, indices, forex, crypto and futures.
The message tells you which problem it is
The message tells you which problem it is, so read it before you change anything:
| Message | What it means | Fix |
|---|---|---|
| You are not entitled to this data... | The plan does not cover this product or tier | Match the product and tier to the request, below |
| Your plan doesn't include this data timeframe... | You hold the product, but not for these dates: too recent for a delayed tier, or older than the tier's history window | Retry on a date inside your plan's window; if that works, the tier is the limit |
| forbidden, on flat files | The dataset is not in your plan, or the exchange agreements are unsigned; the response cannot tell which | Check the File Browser for the plan, then complete the agreements at massive.com/dashboard/agreements |
If your plan covers the dataset and the download is still refused, it is the agreements, and completing them is the fix.
How to fix a not-authorized response
- Work out which product the request belongs to, using the table below.
- Open massive.com/dashboard/products and check which products and tiers your key carries.
- If the product is missing, subscribe to it. If you hold the product but the request needs a higher tier, such as real-time quotes on a delayed plan, upgrade the tier or move to an endpoint your tier covers.
- If it is a product you do not need, change the request instead. An ETF such as SPY is a stock, so its trades come from the Stocks product even though it tracks an index.
Every REST endpoint and WebSocket cluster belongs to exactly one product. This table maps a request to the subscription that unlocks it:
| What you are calling | Product that unlocks it |
|---|---|
| A stock ticker such as AAPL or SPY on /v2/aggs, /v3/trades, /v3/quotes, /v2/last/trade, /v2/last/nbbo or the stocks snapshot | Stocks |
| An options contract such as O:SPY251219C00650000, or /v3/snapshot/options/{underlying} | Options |
| An index such as I:SPX, or /v3/snapshot/indices | Indices |
| A forex pair such as C:EURUSD | Currencies |
| A crypto pair such as X:BTCUSD | Currencies |
| Any /futures/v1/ endpoint | Futures |
| A WebSocket cluster, such as wss://socket.massive.com/stocks | A paid real-time tier of that product. A delayed tier, such as Stocks Starter, connects to wss://delayed.massive.com instead |
Why this happens
This happens because Massive entitles a key per product and per tier rather than per account. Buying Indices Advanced grants every Indices endpoint in real time and grants nothing under Stocks, so a stocks trades call with that key is refused even though the key and the payment are both fine. Within one product the free Basic tier serves end-of-day data at five requests a minute, the paid tiers add history and unlimited requests, and the Advanced tier adds real-time data. Entitlement is attached to the account's products rather than to a key, so an upgrade reaches every key you already hold and you do not need to generate a new one.
On a WebSocket it arrives at subscribe, not at connect
Authentication succeeds on every cluster whatever your plan covers, so auth_success is not evidence that your key is entitled to anything. The refusal comes back in reply to the subscribe message:
[{"ev":"status","status":"auth_success","message":"authenticated"}]
[{"ev":"status","status":"error","message":"not authorized"}]
Two things follow. Read the reply to every subscribe rather than only the auth, because that is where the refusal appears. And check the channel name before you check your plan: the same message answers a channel that exists on a different cluster, which makes a typo look like a billing problem. Per-second aggregates are A on the stocks, options, indices and futures clusters but XAS on crypto and CAS on forex, so A.* on the crypto cluster returns "not authorized" from a fully entitled key.
A channel name we do not recognize at all behaves differently again: the subscribe is neither acknowledged nor refused, and the connection just stays silent. So silence after auth_success points at a spelling mistake, while "not authorized" points at either the wrong cluster or the wrong plan. The WebSocket documentation lists every channel.
If you see an error
{"status":"NOT_AUTHORIZED","message":"You are not entitled to this data. Please upgrade your plan at https://massive.com/pricing"} with HTTP 403 means the key is valid but its plan does not cover this endpoint or this data. Match the product and tier to the request, as above.
A single ticker refused inside a response that otherwise succeeds, as {"ticker":"I:NQEM4040LMN","error":"NOT_ENTITLED","message":"Not entitled to this ticker."} in a snapshot, means that one ticker is outside your plan.
A refusal just after an upgrade can mean the change has not reached your account yet. Wait a few minutes and retry the same request before contacting support.
{"status":"ERROR","error":"API Key was not provided"} with HTTP 401 means the request reached Massive with no key at all. Add ?apiKey=YOUR_API_KEY to the URL, or send the key as Authorization: Bearer KEY. Both work; a Bearer prefix is required in the header form.
{"status":"ERROR","error":"Unknown API Key"} with HTTP 401 means the key is not one we recognize, usually a typo or a deleted key. Copy it again from massive.com/dashboard/keys.
{"ev":"status","status":"error","message":"not authorized"} on a WebSocket means either the plan does not cover that feed or the channel name is wrong for that cluster. Check the channel name first, because it costs nothing.
{"ev":"status","status":"error","message":"You don't have access real-time data..."} in reply to a subscribe on wss://socket.massive.com means the key cannot receive real-time data on that cluster: its tier of that product is delayed, or the exchange agreements on a real-time plan are unsigned. Connect a delayed tier to wss://delayed.massive.com, or see I paid for real-time Massive data, so why is it still delayed or refused?.

