From 552192428cef90a8e2d1f0928fe3ecdc38cbb161 Mon Sep 17 00:00:00 2001 From: Manuel Polo Date: Mon, 25 May 2026 19:27:11 +0000 Subject: [PATCH 1/4] feat: regenerate client for auth token endpoint (0.3.0) Picks up OpenAPI spec 0.95.0: - New AuthApi.auth() method against POST /auth/token - AuthTokenResponse and AuthError models - apiKeyAuth (X-API-Key) security scheme Also carries forward additive schema changes from a prior missed regen: EquityPoint, ResultMap.pnlTotalPercent, and ResultMap.equityCurve. README drive-by: switch quickstart env var from JWT_API_TOKEN to QTSURFER_TOKEN, matching the TS and Python clients. --- CHANGELOG.md | 11 +++++++++++ README.md | 9 +++++---- pom.xml | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2dc942..b5db72f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] +## [0.3.0] — 2026-05-25 + +### Added + +- `AuthApi.auth()` — exchange an API key for a short-lived JWT against `POST /auth/token` (OpenAPI spec 0.95.0). The client now ships `AuthTokenResponse` and `AuthError` models and an `apiKeyAuth` (`X-API-Key`) security scheme. +- `EquityPoint` model and `ResultMap.pnlTotalPercent` / `ResultMap.equityCurve` fields, carried forward from a prior spec bump that had not been regenerated here. + +### Fixed + +- README quickstart now reads the JWT from `QTSURFER_TOKEN` (was `JWT_API_TOKEN`), matching the TS and Python clients. + ## [0.2.0] — 2026-05-17 ### Changed diff --git a/README.md b/README.md index fc51e3a..20f3779 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Add the JitPack repository and the dependency: com.qtsurfer api-client-java - 0.2.0 + 0.3.0 ``` @@ -49,12 +49,12 @@ For Gradle: ```gradle repositories { maven { url 'https://jitpack.io' } } -dependencies { implementation 'com.qtsurfer:api-client:0.2.0' } +dependencies { implementation 'com.qtsurfer:api-client:0.3.0' } ``` ### Via Maven Central (future) -Once published to Central, the coordinate will be `com.qtsurfer:api-client:0.1.2`. +Once published to Central, the coordinate will be `com.qtsurfer:api-client:0.3.0`. ## Quick start @@ -68,7 +68,7 @@ import java.util.List; ApiClient client = new ApiClient(); client.updateBaseUri("https://api.qtsurfer.net/v1"); client.setRequestInterceptor(builder -> - builder.header("Authorization", "Bearer " + System.getenv("JWT_API_TOKEN"))); + builder.header("Authorization", "Bearer " + System.getenv("QTSURFER_TOKEN"))); ExchangeApi exchanges = new ExchangeApi(client); List result = exchanges.getExchanges(); @@ -78,6 +78,7 @@ List result = exchanges.getExchanges(); | API class | Methods | | --- | --- | +| `AuthApi` | `auth()` — exchange API key for a short-lived JWT | | `ExchangeApi` | `getExchanges()`, `getInstruments(exchangeId)` | | `ExchangeBinaryDownloads` | `getTickersHour(...)`, `getKlinesHour(...)` — Lastra/Parquet streams (manual; see note below) | | `StrategyApi` | `postStrategy(body, xCompileAsync)`, `getStrategyStatus(strategyId)` | diff --git a/pom.xml b/pom.xml index 4e1ff64..8c3cac9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.qtsurfer api-client - 0.2.0 + 0.3.0 jar QTSurfer API Client From bc70798ad2d0743aa0642ee852d861c1094d15ec Mon Sep 17 00:00:00 2001 From: Manuel Polo Date: Mon, 25 May 2026 20:32:05 +0000 Subject: [PATCH 2/4] feat: regenerate client for openapi 0.95.1 (AuthError -> AuthTokenError) Picks up the AuthError schema rename in spec 0.95.1 (symmetric with AuthTokenResponse). All other contract details unchanged. Generated model class renamed at build time: - AuthError -> AuthTokenError Bumps com.qtsurfer:api-client to 0.3.1. --- CHANGELOG.md | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5db72f..3586b1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] -## [0.3.0] — 2026-05-25 +## [0.3.1] — 2026-05-25 ### Added -- `AuthApi.auth()` — exchange an API key for a short-lived JWT against `POST /auth/token` (OpenAPI spec 0.95.0). The client now ships `AuthTokenResponse` and `AuthError` models and an `apiKeyAuth` (`X-API-Key`) security scheme. +- `AuthApi.auth()` — exchange an API key for a short-lived JWT against `POST /auth/token` (OpenAPI spec 0.95.1). The client now ships `AuthTokenResponse` and `AuthTokenError` models and an `apiKeyAuth` (`X-API-Key`) security scheme. - `EquityPoint` model and `ResultMap.pnlTotalPercent` / `ResultMap.equityCurve` fields, carried forward from a prior spec bump that had not been regenerated here. ### Fixed diff --git a/pom.xml b/pom.xml index 8c3cac9..04537be 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.qtsurfer api-client - 0.3.0 + 0.3.1 jar QTSurfer API Client From e913e209c884bb4dfb056299f0b4266aa4871b5e Mon Sep 17 00:00:00 2001 From: Manuel Polo Date: Mon, 25 May 2026 20:54:04 +0000 Subject: [PATCH 3/4] docs(auth): add API key -> JWT snippet and SDK cross-link Generator regen does not touch the README. Add a short usage snippet showing how to call `AuthApi.auth()` with an ApiClient configured to send X-API-Key via setRequestInterceptor, document the QTSURFER_APIKEY env-var convention, and point production callers at the sibling SDK for token-refresh handling. Part of openapi-auth-rollout Phase 2 (#168). --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 20f3779..37720b6 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,30 @@ ExchangeApi exchanges = new ExchangeApi(client); List result = exchanges.getExchanges(); ``` +### API key → JWT + +Every endpoint above expects a short-lived JWT in `Authorization: Bearer …`. +Exchange a long-lived API key for one via `AuthApi.auth()`: + +```java +import com.qtsurfer.api.client.api.AuthApi; +import com.qtsurfer.api.client.invoker.ApiClient; +import com.qtsurfer.api.client.model.AuthTokenResponse; + +ApiClient apikeyClient = new ApiClient(); +apikeyClient.updateBaseUri("https://api.qtsurfer.net/v1"); +apikeyClient.setRequestInterceptor(builder -> + builder.header("X-API-Key", System.getenv("QTSURFER_APIKEY"))); + +AuthTokenResponse token = new AuthApi(apikeyClient).auth(); +String jwt = token.getAccessToken(); // feed to a Bearer-authed ApiClient +``` + +For production use, prefer the [`com.qtsurfer:sdk`](https://github.com/QTSurfer/sdk-java) +`auth(apikey)` helper — it returns an `AuthenticatedClient` that refreshes the +JWT transparently, reads `QTSURFER_APIKEY` from the environment, and supports +pluggable token stores so callers don't reinvent that plumbing. + ## API surface | API class | Methods | From ebe52fe47640ac9aa2e44f5995bbf29ef8a4d541 Mon Sep 17 00:00:00 2001 From: Manuel Polo Date: Mon, 25 May 2026 21:13:43 +0000 Subject: [PATCH 4/4] docs(readme): use api.qtsurfer.com (prod target) not .net (pre) A prior drive-by edit in this PR replaced 'api.qtsurfer.com' with 'api.qtsurfer.net' to match what was running in pre. That direction is wrong: the documented base URL in README quickstarts should reflect the production target, which is .com. .net is the staging / pre-prod host that adopters do not need to know about. This restores the three quickstart snippets (Exchange, Auth, ExchangeBinaryDownloads) to api.qtsurfer.com, aligning Java with api-client-python and api-client-ts. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 37720b6..868b677 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ import com.qtsurfer.api.client.model.Exchange; import java.util.List; ApiClient client = new ApiClient(); -client.updateBaseUri("https://api.qtsurfer.net/v1"); +client.updateBaseUri("https://api.qtsurfer.com/v1"); client.setRequestInterceptor(builder -> builder.header("Authorization", "Bearer " + System.getenv("QTSURFER_TOKEN"))); @@ -85,7 +85,7 @@ import com.qtsurfer.api.client.invoker.ApiClient; import com.qtsurfer.api.client.model.AuthTokenResponse; ApiClient apikeyClient = new ApiClient(); -apikeyClient.updateBaseUri("https://api.qtsurfer.net/v1"); +apikeyClient.updateBaseUri("https://api.qtsurfer.com/v1"); apikeyClient.setRequestInterceptor(builder -> builder.header("X-API-Key", System.getenv("QTSURFER_APIKEY"))); @@ -135,7 +135,7 @@ The class reuses the `ApiClient`'s `HttpClient` and request interceptor, so any `ApiClient` exposes the underlying `HttpClient.Builder` and an `ObjectMapper`, plus hooks for request/response interceptors. ```java -client.updateBaseUri("https://api.qtsurfer.net/v1"); +client.updateBaseUri("https://api.qtsurfer.com/v1"); client.setRequestInterceptor(builder -> builder.header("Authorization", "Bearer " + token)