Skip to content

What you can do

Describes @stxapp/stx-typescript 0.9.0, the current release.

One SDK works against every STX exchange. Not every exchange has every feature yet: OAuth apps are on US demo first, for example. A call that needs a feature the exchange does not have throws STXNotAvailableException, and capabilities() tells you up front, so the same code runs against Ontario production today and picks up new features as each exchange gets them.

Feature Id SDK calls Guide
Markets, events and prices markets(), iterMarkets(), market(), events(), iterEvents(); channels ws.ticker(), ws.market(), ws.orderbook(), ws.trades(), ws.marketStats(), ws.marketUpdates() Markets, WebSockets
Trading placeOrder(), placeOrders(), cancelOrder(), cancelOrders(), cancelAllOrders(), order(), orders() Trading
Your account me(), balance(), positions(), fills(), settlements(), deposits(), withdrawals(), fees(), accountMarketStats(); channels ws.accountView(), ws.balances(), ws.orders(), ws.fills(), ws.positions(), ws.settlements() Portfolio
Event players event_players eventPlayers(), statsFor() Markets
Leaderboard and public profile leaderboard leaderboard(), leaderboardMe(), updateProfile() Leaderboard
Combos combos ws.comboPlayer(), ws.comboMaker() Combos
OAuth oauth discoverMetadata(), OAuthClient.discover() Build an app
Members connect their STX account oauth.member oauth.beginAuthorization(), oauth.completeAuthorization(), oauth.memberClient(), oauth.refreshToken(), oauth.unlink(), oauth.revoke() Sign in with STX
App tokens oauth.app oauth.appClient(), oauth.appToken(), oauth.clientCredentials() Acting as your app
Sign in with STX connect createConnect(): start(), finish(), refresh(), disconnect(), userInfo() Sign in with STX
Terms accepted on an STX page terms.stx_page STXTermsRequiredException.termsUrl, termsUrlWithReturn(), the onTermsRequired session hook When STX has new terms
Creating markets markets.create createMarkets() (with dryRun), as an app holding markets.write Creating markets
Market types market_types marketTypes() Creating markets

Features without an id are on every exchange. Members still being verified (STXAccountPendingException) and IP allow-list refusals (STXIPNotAllowedException) come with OAuth wherever it is on.

Checked against the live exchanges on 2026-10-21, and Ontario demo again on 2026-10-23.

Feature US demo (demo.stxapp.io) Ontario demo (demo.stxapp.ca) Ontario production (api.on.stxapp.ca)
Markets, trading, your account yes yes yes
event_players yes yes yes
leaderboard yes no no
oauth yes no no
oauth.member yes no no
oauth.app yes no no
connect yes no no
terms.stx_page yes no no
markets.create yes no no
market_types yes no no
Exchange version (/api_version) 3.3.196 3.3.194-5 3.3.186-6

Exchanges gain features with their releases, so ask the exchange rather than this table when your code needs to know.

import { STX } from "@stxapp/stx-typescript";
const stx = new STX({ environment: "ontario-demo" });
const caps = await stx.capabilities();
console.log(caps.toJSON());

On Ontario demo:

{
"host": "demo.stxapp.ca",
"apiVersion": "3.3.194-5",
"checkedAt": "2026-10-23T17:37:03.512Z",
"scopesSupported": [],
"features": {
"oauth": false,
"oauth.member": false,
"oauth.app": false,
"connect": false,
"terms.stx_page": false,
"markets.create": false,
"market_types": false,
"event_players": true,
"leaderboard": false,
"combos": true
}
}

On US demo every feature is true, and scopesSupported is the list the exchange publishes:

[
"openid", "profile.read", "balance.read", "portfolio.read", "orders.read",
"transfers.read", "orders.write", "market_data", "events", "markets.write"
]
  • caps.features.combos is true, false, or null when it could not be checked (a check that needs credentials on a client without them, or an exchange that did not answer).
  • caps.has("combos") is true only when the exchange is known to have it.
  • caps.require("combos") throws STXNotAvailableException when the exchange is known not to have it.

The answer is cached on the client; capabilities({ refresh: true }) checks again. A missing feature never makes capabilities() or new STX() throw, and the calls you already make are unaffected: only a call that needs the missing feature throws.

Every check reads what the exchange publishes. Nothing is created, changed or cancelled.

Id Available when
oauth GET /.well-known/oauth-authorization-server returns the discovery document. A 404, or a 403 page from in front of the exchange (not JSON), means no.
oauth.member OAuth is on, grant_types_supported lists authorization_code, and scopes_supported lists a member scope such as orders.read.
oauth.app OAuth is on and grant_types_supported lists client_credentials.
connect OAuth is on and scopes_supported lists openid.
terms.stx_page Members can connect and scopes_supported does not list terms.write.
markets.create App tokens are on and scopes_supported lists markets.write.
market_types A signed GET /api/v1/types answers. A 404 with {"error": "not_found"} (no such route) means no.
event_players A signed GET /api/v1/events/{event_id}/players for an event that does not exist answers 404 {"error": "event not found"}. A 404 {"error": "not_found"} means no such route.
leaderboard A signed GET /api/v1/leaderboard?limit=1 answers. A 404 (no such route, or {"error": "Leaderboard is not enabled"}) means no.
combos A join of the combo player topic for a user id nobody has is refused as unauthorized. unmatched topic means the exchange has no combo topics.

The OAuth discovery document and its fields are described in OAuth, and the combo topics in Combo negotiation.

STXNotAvailableException extends STXAPIException, so it is an STXException like every other SDK error. It carries:

  • feature: the id from the tables above, or scope:<name> for a scope the exchange does not offer.
  • host: the exchange that answered.
  • message: a sentence naming both.
  • statusCode and body: the answer it was decided from, when there was one.

Captured on Ontario demo on 2026-10-21:

await stx.marketTypes();
// STXNotAvailableException: Market types are not available on demo.stxapp.ca yet.
// feature: "market_types", host: "demo.stxapp.ca", statusCode: 404, body: { error: "not_found" }
await discoverMetadata("https://demo.stxapp.ca");
// STXNotAvailableException: OAuth is not available on demo.stxapp.ca yet.
// feature: "oauth", host: "demo.stxapp.ca", statusCode: 404

STXCombosUnavailableException is still the channel exception it was, and instanceof STXNotAvailableException is true for it too, so either catch works:

import { STXNotAvailableException } from "@stxapp/stx-typescript";
try {
const player = await ws.comboPlayer();
// ...
} catch (err) {
if (err instanceof STXNotAvailableException) {
console.log(`${err.feature} is not on ${err.host} yet; hiding combos`);
} else {
throw err;
}
}

Which calls throw it, by feature:

Id Throws from
combos ws.comboPlayer(), ws.comboMaker()
oauth discoverMetadata(), OAuthClient.discover(), and any token, refresh, revoke or introspect call on an exchange without OAuth
connect createConnect() calls, when the exchange has no OpenID configuration or userinfo endpoint
market_types marketTypes()
event_players eventPlayers(), statsFor()
leaderboard leaderboard(), leaderboardMe(), updateProfile()
markets.create createMarkets()
scope:<name> clientCredentials(), appClient() calls and completeAuthorization(), when the exchange answers invalid_scope for a scope its discovery document does not list (the client must come from OAuthClient.discover() or fromMetadata() to know the list)