If you are reading this article, chances are you have obtained a free API key from polygon.io and that you are ready to try out their websocket for market data streaming. However, you are greeted with the dreadful message:
{"ev":"status",
"status":"error",
"message":"authentication failed"
}
In order to spare you from the frustration and agony, let's simply point out that there may not be anything wrong with your code or the API key - it's simply a matter of payment. But first, let's rule out all the other causes.
At the time of writing, the following results were available on Google search:
Now, to further save you time, here is the gist of each thread.
1. GitHub / AlpacaHQ discussion
The RESTful API works but the websocket API fails at authentication. Someone pointed out a different cluster should be used (maybe a different endpoint?). Then someone else later pointed out that the previously experimental service was now fully supported... until another user later pointed out, that his previously functional C# code snippet suddenly stopped working. This thread was left hanging.
2. GitMemory / Alpaca Markets Forum
Alpaca is not Polygon. However, an Alpaca user can use a white-labeled endpoint to fetch polygon streamed data. As the thread points out, an Alpaca API key can work in place of a key from polygon.io. In Alpaca's documentation, it is also explained that only a live (paid) Alpaca account has a functional streaming API key. Despite its conclusive presence, this forum does not answer our question. The "authentication failed" error with polygon.io is not an old issue. It has not been resolved.
3. StackOverflow
The lucky OP actually managed to authenticate! But their secondary issue, namely the complaint of "too many concurrent connections", was not addressed. For the record, the OP's code has structural issues and can be better diagnosed with Firefox Developer's Network/WS view. We'll cover this in another post. The responses to the StackOverflow thread were not only not helpful, but also representative of the community support landscape of many "modern" products. Instead of delving into the true causes, the solutions suggest trying out different library packages. We can't tell whether it's a python thing, or a problem with a generation of programmers who can't be bothered to learn to build things from the ground up. They'd rather cradle themselves with ready-to-go PIP or NPM modules. Oh the microwave chefs think that they can "cook" by reheating Uber Eats meals.
4. /r/algotrading
Reddit is not a suitable place to discuss technical matters. StackOverflow would have worked better. It's no surprise that this thread went nowhere. The only takeaway is that someone tried and resorted to RESTful API. Since this Reddit thread is closed, we'll be reaching out to the original poster as well as other interested parties who are identified in the discussion.
Now, having done our research due diligence, here is why our specific case of the websocket API use failed. It was a matter of payment:
Sure enough, the product comparison page on polygon.io states one overlooked element - the plan:
What happened here was that Polygon assumed that a prospective customer would read about their products and pricing plans first. Polygon also assumed that the focus of a product evaluation is the quality of their data. Leaving websocket out would still qualify their basic plan a great test drive.
The reality is that there are aggregators and integrators who would simply look at all the websocket providers. In our use case, we are measuring the pricing propagation delay across multiple crypto markets.
Like many badly written APIs, polygon's error message was misleading. "authentication failed" means many things. Could the API key be wrong or invalidated? Would a "invalid subscription" be a better, and time-saving response?
Polygon.io's documentation takes a step further to mislead the developers:
In fact, this was the first page we landed on. The "Free API Key" button is paired up with the Websocket Documentation. If websocket is not covered by the free tier, wouldn't be suitable to disable the button?
WebSocket Authentication from First Principle
A WebSocket is a JavaScript object that opens a TCP connection between the browser and the server. In addition to the typical 3-way TCP handshake, a websocket channel takes one extra step of handshake. Some services use this step to prevent unauthorized users from connecting.
When polygon.io talks about "authentication" it has nothing to do with the WS handshake. Maybe it has become common practice in many client libraries, but as far as the protocol is concerned, there is no such thing as channel "authentication", or "subscription" for that matter. A websocket, once opened, can send. The Polygon API expects a JSON encoded STRING of the following format:
{"action":"auth", "params":"API_KEY"}
So the following code should work:
document.ws=new WebSocket('wss://api.polygon.io/crypto');
document.ws.onopen=function(e){
var auth='{"action":"auth", "params":"API_KEY"}';
document.ws.send(auth);
}
The following code would NOT work:
var auth={"action":"auth", "params":"API_KEY"};
document.ws.send(auth);
However, one can stringify the object:
var auth={"action":"auth", "params":"API_KEY"};
document.ws.send(JSON.stringify(auth));
This seems straightforward enough. However, when the "authentication failed" error is thrown back, one can only speculate what might have happened on the server-side. Maybe the parser is picky about the spacing between each element? Maybe the "params" field needs to be encoded differently? Maybe the payload needs to be sent as a BLOB? Maybe the quotations around the keys (action, params), should be omitted?
We have tried ALL the combinations without success. After all, it's a matter of payment!
The Alternatives
polygon.io is not the only player in the game. It is not even a good player. Depending on your data requirements, consider the following alternative websocket providers:
BitMex [documentation]
The public streaming API from BitMex works like a charm. No authentication and no fuss. The data is clean, and the documentation is to-the-point. As a trading platform, BitMex is banned in the US and a few other countries, but this should not affect the availability of their data.
BitMex has limited selection of crypto symbols. If you need to get data on Stellar or Monero, for example, you'll have to look elsewhere.
CryptoWatch [documentation]
CryptoWatch requires an account. They have a very general initial allowance and bandwidth-based pricing plan. The amount of data CryptoWatch offers could be overwhelming. Instead of sending responses in plain text, they are in BLOBs.
The following code won't work with CryptoWatch's websocket response:
document.ws.onmessage=function(e){
var obj=JSON.parse(e.data);
}
We need a FileReader to asynchronously process the potentially large sized responses:
document.ws.onmessage=function(e){
var reader = new FileReader();
reader.onload=function(){
var obj=JSON.parse(reader.result);
}
reader.readAsText(e.data);
}