@tronchartsxyz/api-client
v0.4.0
Published
TypeScript SDK for the TRON Charts Provider API (REST + WSS).
Maintainers
Readme
@tronchartsxyz/api-client
TypeScript SDK for the Tron Charts Provider API.
Covers the REST surface at /api/v1/* and the Risk Engine
WebSocket surface at /ws/risk. Hand-written; types track the
openapi.yaml + asyncapi.yaml specs in docs/api/.
Execution model — read this before reconciling
An order reaches the market one of two ways, and venue tells you
which:
- Routed (A-book) — signed and dispatched to the named exchange.
venueis that exchange;venueOrderId/venueTradeIdare the exchange's own ids and reconcile against its records. - Internalised (B-book) — the firm is the counterparty. Our own engine matches the order against a firm-canonical mark and no order is placed at any exchange. The firm hedges its aggregate exposure separately, on its own account; that hedge is not on your account and is not reported here.
Internalised rows carry venue: 'paper'. The sentinel means "matched
by our engine", not "simulated money" — it covers the sandbox and
internalised real-money accounts, which settle real PnL. Which one
applies is a property of the account (its execution mode), never
of the venue string.
So: venueOrderId and venueTradeId are string | null. On an
internalised execution they are ids we minted for the internal match —
stable, safe as dedup keys, and resolvable nowhere off-platform. Do
not build exchange-side reconciliation on them, and do not treat
venue === 'paper' as "this account is a demo".
Install
For now, consume directly from the monorepo path:
// tsconfig.json paths
{
"compilerOptions": {
"paths": {
"@tronchartsxyz/api-client": ["./packages/api-client-ts/src/index.ts"]
}
}
}A standalone npm publish lands once the API surface stabilizes (post Track D W11-12).
REST
import { TronCharts } from '@tronchartsxyz/api-client'
const sdk = new TronCharts({
baseUrl: 'https://trade.your-domain.com',
token: process.env.TRON_CHARTS_TOKEN!,
tenantSlug: 'acme', // optional; defaults to the platform tenant
})
// Account state
const state = await sdk.accounts.state('account-uuid')
console.log(state.balanceUsd, state.positions)
// Compose + dispatch an intent
const { intentId } = await sdk.oms.composeIntent({
accountId: 'account-uuid',
venue: 'hyperliquid',
symbol: 'BTC.HL',
side: 'buy',
qty: '0.05',
type: 'market',
}, crypto.randomUUID()) // idempotency key
// Cursor-paginated orders
for await (const order of paginate(
(cursor) => sdk.accounts.orders('account-uuid', { cursor: cursor ?? undefined }),
)) {
console.log(order.symbol, order.state)
}
// SOR savings summary
const summary = await sdk.sor.summary({ from: '2026-04-01T00:00:00Z' })
console.log(`saved $${summary.totalCostSavedUsd}`)Errors
Every non-2xx throws TronChartsApiError:
import { TronChartsApiError } from '@tronchartsxyz/api-client'
try {
await sdk.oms.composeIntent({ /* ... */ })
} catch (e) {
if (e instanceof TronChartsApiError) {
console.error(e.code, e.status, e.detail)
}
}Idempotency
Pass an idempotencyKey to mutating calls. The BE replays the
prior response for any retry under the same key, per Stripe's
pattern.
WebSocket
import { RiskEngineClient } from '@tronchartsxyz/api-client'
const ws = new RiskEngineClient({
url: 'wss://trade.your-domain.com/ws/risk',
token: process.env.TRON_CHARTS_TOKEN!,
onFrame: (frame) => {
if (frame.type === 'Order-Intent-Update') {
console.log('order update', frame.payload)
}
},
onError: (err) => console.error(err),
onReconnected: () => console.log('reconnected; resubscribe topics'),
})
await ws.connect()
ws.send({ type: 'Subscribe', topic: 'account.*' })
ws.send({ type: 'Get-open-orders', accountId: 'account-uuid' })
// ... later
ws.close()Heartbeat (30s default), reconnect with exponential backoff (1s →
30s), and the Authenticate handshake are handled by the client.
The caller resubscribes topics on onReconnected.
Node usage
globalThis.WebSocket is only available in Node 22+. For older
runtimes, pass a polyfill:
import WebSocket from 'ws'
new RiskEngineClient({ /* ... */, WebSocketImpl: WebSocket as any })Versioning
The SDK version tracks openapi.yaml info.version. Breaking
changes ship as a new SDK major.
What's not yet covered
- Reports endpoints other than
orders,fills,daily-pnl - Earn (deposit/withdraw calldata)
- Symbols discovery
- LLM co-pilot SSE (needs special streaming handling)
- Webhook subscription CRUD (admin-only — different surface)
Add as Track D matures. Open a PR.
