diff --git a/CHANGELOG.md b/CHANGELOG.md index 094c42d..6651cb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,15 @@ All notable changes to the `cryptohopper` gem are documented in this file. The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). -## 0.1.0.pre.alpha.1 — Unreleased +## 0.1.0.pre.alpha.2 — Unreleased + +### Fixed +- **Critical: every authenticated request was rejected by the API gateway.** The transport sent `Authorization: Bearer `, which the AWS API Gateway in front of `api.cryptohopper.com/v1/*` rejects (`405 Missing Authentication Token`). Cryptohopper's Public API v1 uses `access-token: ` — confirmed by the official [API documentation](https://www.cryptohopper.com/api-documentation/how-the-api-works) and the legacy iOS/Android SDKs. Switching to send `access-token`. The `Authorization` header is no longer set. + +### Compatibility +No public-API change. `client.user.get`, `client.hoppers.list`, etc. keep their signatures. + +## 0.1.0.pre.alpha.1 — 2026-04-24 Initial release. Launches at full surface parity with the other SDKs at 0.4.0 — all 18 public API domains from day one. diff --git a/README.md b/README.md index 33111b0..5fe513c 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ ch.hoppers.buy(hopper_id: 42, market: "BTC/USDT", amount: 0.001) ch.hoppers.config_update(42, strategy_id: 99) ch.hoppers.panic(42) -# Exchange (public, no auth) +# Exchange — market data (still requires a real token; the gateway has no anonymous routes) ch.exchange.ticker(exchange: "binance", market: "BTC/USDT") ch.exchange.candles(exchange: "binance", market: "BTC/USDT", timeframe: "1h") diff --git a/lib/cryptohopper/client.rb b/lib/cryptohopper/client.rb index ca50bdd..03d4086 100644 --- a/lib/cryptohopper/client.rb +++ b/lib/cryptohopper/client.rb @@ -136,7 +136,10 @@ def build_request(method, uri, body) end req = klass.new(uri.request_uri) - req["Authorization"] = "Bearer #{@api_key}" + # Cryptohopper Public API v1 uses `access-token: `, not the + # OAuth2-conventional `Authorization: Bearer `. The gateway + # in front of the API rejects Bearer with a SigV4 parse error. + req["access-token"] = @api_key req["Accept"] = "application/json" req["User-Agent"] = user_agent_header # Ruby treats empty strings as truthy, so a literal `if @app_key` diff --git a/lib/cryptohopper/version.rb b/lib/cryptohopper/version.rb index ac1603e..1a28c4d 100644 --- a/lib/cryptohopper/version.rb +++ b/lib/cryptohopper/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Cryptohopper - VERSION = "0.1.0.pre.alpha.1" + VERSION = "0.1.0.pre.alpha.2" end diff --git a/spec/cryptohopper/client_spec.rb b/spec/cryptohopper/client_spec.rb index bcadfcb..9433fc9 100644 --- a/spec/cryptohopper/client_spec.rb +++ b/spec/cryptohopper/client_spec.rb @@ -23,11 +23,11 @@ def build_client(**opts) end describe "transport" do - it "sends Authorization + User-Agent headers and unwraps {data}" do + it "sends access-token + User-Agent headers and unwraps {data}" do stub_request(:get, "https://api.cryptohopper.com/v1/user/get") .with( headers: { - "Authorization" => "Bearer ch_test", + "access-token" => "ch_test", "Accept" => "application/json", "User-Agent" => "cryptohopper-sdk-ruby/#{Cryptohopper::VERSION}" } @@ -39,6 +39,16 @@ def build_client(**opts) expect(out).to eq({ "hello" => "world" }) end + it "does not send an Authorization header" do + stub_request(:get, "https://api.cryptohopper.com/v1/user/get") + .to_return(status: 200, body: '{"data":{}}') + build_client.send(:_request, "GET", "/user/get") + expect(WebMock).to( + have_requested(:get, "https://api.cryptohopper.com/v1/user/get") + .with { |req| req.headers["Authorization"].nil? } + ) + end + it "sends x-api-app-key when app_key is provided" do stub_request(:get, "https://api.cryptohopper.com/v1/user/get") .with(headers: { "x-api-app-key" => "client_123" })