Quickstart
Install the SDK, drop in an SDK environment minted from the Tria app, and place your first order. This page gets you trading on either venue; the Credentials page explains where the keys come from.
Install
npm install @tria-sdk/api-trading
Runtime targets: Node 18+ (native fetch) and modern evergreen browsers. The package ships dual ESM + CJS builds; bundlers pick the right entry automatically. No React, wallet provider, or other runtime infrastructure required — it's a pure client library.
You need an SDK environment (an agent/delegate keypair authorized for
trade-only) before you can place orders. Generate one from the Tria app's
Settings → API Keys page or the npx tria-trade-provision wizard — see
Credentials.
Hyperliquid
import { TriaClient } from '@tria-sdk/api-trading'
import { randomBytes } from 'node:crypto'
const client = new TriaClient({
network: 'mainnet',
hl: {
agentPrivateKey: process.env.TRIA_TRADE_HL_AGENT_KEY!,
accountAddress: process.env.TRIA_TRADE_HL_ACCOUNT_ADDRESS!,
},
})
const cloid = '0x' + randomBytes(16).toString('hex')
await client.placeOrder({
venue: 'hl',
market: 'BTC',
side: 'buy',
size: '0.0003', // BTC, decimal string
price: '50000', // USD limit, decimal string
tif: 'gtc',
clientOrderId: cloid,
})
// `clientOrderId` is your dedup key — re-using a live one is rejected, so a
// retry can't double the order. Cancel by it or the venue orderId.
await client.cancelOrder({ venue: 'hl', clientOrderId: cloid })
Decibel
import { TriaClient } from '@tria-sdk/api-trading'
const client = new TriaClient({
network: 'mainnet',
decibel: {
delegatePrivateKey: process.env.TRIA_TRADE_DECIBEL_DELEGATE_KEY!,
// Master Aptos address — the SDK derives the primary subaccount from this.
aptosOwnerAddress: process.env.TRIA_TRADE_DECIBEL_APTOS_OWNER_ADDRESS!,
// Geomi read key — required (Decibel rejects anonymous reads with 401).
nodeApiKey: process.env.TRIA_TRADE_DECIBEL_NODE_API_KEY,
// Geomi gas-station key — optional. When set, Aptos writes are sponsored.
gasStation: process.env.TRIA_TRADE_DECIBEL_GAS_STATION_KEY,
},
})
await client.placeOrder({
venue: 'decibel',
market: 'BTC/USD', // note the slash — Decibel's naming convention
side: 'buy',
size: '0.0003',
price: '50000',
tif: 'gtc',
clientOrderId: 'my-bot-2026-05-23-001', // any non-empty string
// Optional TP/SL attached to THIS entry (Decibel sets TP/SL at placement
// time). On HL, use attachTpSl after the fill instead.
tpTriggerPrice: '60000',
slTriggerPrice: '45000',
})
Both venues from one client
const client = new TriaClient({
network: 'mainnet',
hl: {
agentPrivateKey: process.env.TRIA_TRADE_HL_AGENT_KEY!,
accountAddress: process.env.TRIA_TRADE_HL_ACCOUNT_ADDRESS!,
},
decibel: {
delegatePrivateKey: process.env.TRIA_TRADE_DECIBEL_DELEGATE_KEY!,
aptosOwnerAddress: process.env.TRIA_TRADE_DECIBEL_APTOS_OWNER_ADDRESS!,
nodeApiKey: process.env.TRIA_TRADE_DECIBEL_NODE_API_KEY,
},
})
// One normalized Fill callback across both venues.
await client.subscribeFills({ venue: 'hl' }, (fill) => console.log(fill))
await client.subscribePositions({ venue: 'decibel' }, (positions) => {
console.log(positions)
})
Both hl and decibel are independently optional — configure one or both. Only the configured venues' methods are enabled; calling a venue you didn't configure throws TriaError(INVALID_ARGUMENT).