TypeScript SDK
@tronchartsxyz/api-client wraps the REST surface in typed resources and ships a
WebSocket client for /ws/risk.
Install
Section titled “Install”npm install @tronchartsxyz/api-clientShips as ESM with bundled type declarations; Node 20 or newer. The package has no runtime dependencies.
The REST surface and the OpenAPI spec remain the stable contract — the SDK is a convenience over them, not a replacement, and anything it does not cover you can call directly.
Instantiate
Section titled “Instantiate”import { TronCharts } from '@tronchartsxyz/api-client'
const sdk = new TronCharts({ baseUrl: 'https://api.troncharts.xyz', token: process.env.TRON_CHARTS_TOKEN!, tenantSlug: 'acme', // required unless you call from a registered origin — see Tenancy})tenantSlug is optional in the type signature only. The SDK sends it as
X-Tenant-Slug when present, and every /api/v1/* call needs either that
header or an origin registered on your tenant — otherwise the request 404s with
unknown_tenant_origin before your token is read. See
Tenancy.
Mint the token first. There is no unauthenticated mode — token is required by
the constructor — but auth.apiToken authenticates from the body, so the
minting client can pass an empty string:
const minter = new TronCharts({ baseUrl: 'https://api.troncharts.xyz', token: '' })const { token } = await minter.auth.apiToken({ apiKey, apiSecret })The mint path is one of the few exempt from the tenant gate, so the minting
client needs no tenantSlug either. Every client you build after it does.
Resources
Section titled “Resources”| Resource | Covers |
|---|---|
sdk.auth |
Bootstrap tokens, bearer minting. |
sdk.accounts |
State, positions, orders, trades, lifecycle. |
sdk.oms |
Compose, cancel, modify, brackets. |
sdk.market |
Quotes, depth (flat + grouped), FX. |
sdk.reports |
Historical reconciliation reads. |
sdk.sor |
Routing decisions and savings summary. |
sdk.venues |
Venue capability discovery. |
sdk.propAccounts, sdk.propTemplates, sdk.riskProfiles, sdk.tradingGroups |
The prop surface. |
sdk.firms |
Firm lifecycle — create, readiness, deploy, status, payouts. |
sdk.tenant |
Your tenant’s config. |
sdk.kyc, sdk.referrals, sdk.analytics, sdk.indicators, sdk.backtests, sdk.copyTrading, sdk.sandbox |
The rest of the surface. |
sdk.client is the escape hatch — a raw typed request method for anything the
resources don’t cover yet.
End to end
Section titled “End to end”const sdk = new TronCharts({ baseUrl, token, tenantSlug })
// Rehearse against a sandbox account first.const { accountId } = await sdk.sandbox.paperAccount()
const { intentId } = await sdk.oms.composeIntent( { venue: 'hyperliquid', symbol: 'BTC.HL', side: 'buy', type: 'limit', qty: '0.01', price: '60000' }, crypto.randomUUID(), // idempotency key)
await sdk.oms.attachBrackets({ parentIntentId: intentId, tpPrice: 64000, slPrice: 58000 })
const state = await sdk.accounts.state(accountId)WebSocket client
Section titled “WebSocket client”The socket does not take your REST bearer. Mint a single-use handshake token
with auth.bootstrap() and pass that:
import { RiskEngineClient } from '@tronchartsxyz/api-client'
const { data } = await sdk.auth.bootstrap()
const ws = new RiskEngineClient({ url: data.riskEngineWss.endpoint, token: data.riskEngineWss.token, onFrame: (frame) => { if (frame.type === 'Position-Update') applyPosition(frame) },})
await ws.connect()ws.send({ type: 'Subscribe', topics: ['Position-Changed', 'Open-Orders'] })onFrame is required — there is no .on() event API; every server frame goes
through that one handler. connect() sends Authenticate and nothing else, so
subscribe explicitly for the topics you want. The handshake token is single-use
and expires in 60 seconds, so each connect needs a fresh bootstrap().
The WS client speaks JSON only. If you want the msgpack encoding, drive the socket yourself.
Honest coverage note
Section titled “Honest coverage note”The typed resources track the REST surface but are not a complete mirror of it
— market candles and the trade tape, for one, are REST-only today. When
something is missing, sdk.client.request() reaches it without waiting for an
SDK release. The REST reference renders openapi.yaml,
which is hand-maintained and does not cover every /api/v1 route either — see
Raw specs.