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.

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).

Next steps

Was this page helpful?