Sorry for the late reply, I thought the email reply feature on would auto post to the forum.
Twitch’s documentation is wrong. I did trial and error until I got everything setup.
Twitch’s documentation for bits states that when bits monetization is available, the callback for getting products will succeed, otherwise it will fail.
This is incorrect.
“This function returns a promise which resolves to an array of products available for Bits, for the extension, if the context supports Bits in Extensions actions. Otherwise, the promise rejects with an error;”
But the monetization page (Monetization | Twitch Developers) says
“You can check the twitch.ext.features.isBitsEnabled feature flag to determine if Bits in Extensions features will work in your extension on the current channel.”
Which, also, is a typo. It’s capital T for Twitch.ext.features.isBitsEnabled. Javascript is case sensitive 
I added a check to exit early, inside the getproducts callback using that above variable.
I don’t know what fixed my problem. Because the user DID have bits enabled, but isBitsEnabled was set to false
and the extension DID support bits, and bits were turned ON for the extension. Eventually, after just testing it over and over, it just started working. isBitsEnabled became true (after doing nothing) and it started working.
Also there was another problem. Every single time you do useBits(), twitch REAUTHS the user to a DIFFERENT authorization token. This was breaking my authentication scheme. NO WHERE does it say this behavior exists. It was a race condition of safe checking the values when interacting with a websocket and it’s responses directly after a purchase. I would send the current information after the useBits() response to my backend server via socket, but by the time the data comes back, the auth scheme has changed.
P.S. Also the documentation is wrong for the models that are used in the bits transactions. Both the data inside the jwt and the data given raw. It’s literal trial and error to get it working.
TLDR: When Twitch.ext.features.isBitsEnabled is false, but getProducts() returns a successful promise, if you useBits() it throws that error.