Skip to content

luziadev/sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

@luziadev/sdk

Official TypeScript SDK for the Luzia cryptocurrency pricing API.

Installation

bun add @luziadev/sdk
# or
npm install @luziadev/sdk

Quick Start

import { Luzia } from '@luziadev/sdk'

const luzia = new Luzia({
  apiKey: 'lz_your_api_key',
})

// List all supported exchanges
const exchanges = await luzia.exchanges.list()
console.log(exchanges)
// [{ id: 'binance', name: 'Binance', status: 'operational', ... }]

// Get a single ticker
const ticker = await luzia.tickers.get('binance', 'BTC/USDT')
console.log(`BTC/USDT: $${ticker.last}`)

// Get all tickers for an exchange
const { tickers, total } = await luzia.tickers.list('binance', { limit: 50 })
console.log(`Found ${total} tickers`)

// Get markets with filters
const { markets } = await luzia.markets.list('binance', { quote: 'USDT' })

// Get historical OHLCV candles
const { candles } = await luzia.history.get('binance', 'BTC/USDT', {
  interval: '1h',
  limit: 24,
})
console.log(`Last close: $${candles[candles.length - 1].close}`)

Configuration

const luzia = new Luzia({
  // Required: Your API key
  apiKey: 'lz_xxxxx',

  // Optional: Custom base URL (default: https://api.luzia.dev)
  baseUrl: 'http://localhost:3000',

  // Optional: Request timeout in ms (default: 30000)
  timeout: 10000,

  // Optional: Retry configuration
  retry: {
    maxRetries: 3,        // Number of retry attempts (default: 3)
    initialDelayMs: 1000, // Initial delay before first retry (default: 1000)
    maxDelayMs: 30000,    // Maximum delay between retries (default: 30000)
    backoffMultiplier: 2, // Multiplier for exponential backoff (default: 2)
    jitter: true,         // Add random jitter to delays (default: true)
  },
})

API Reference

Exchanges

// List all supported exchanges
const exchanges = await luzia.exchanges.list()

Tickers

// Get a single ticker
const ticker = await luzia.tickers.get('binance', 'BTC/USDT')

// List all tickers for an exchange
const { tickers, total, limit, offset } = await luzia.tickers.list('binance', {
  limit: 50,
  offset: 0,
})

// Get specific tickers across exchanges
const { tickers } = await luzia.tickers.listFiltered({
  exchange: 'binance',           // Optional: filter by exchange
  symbols: ['BTC/USDT', 'ETH/USDT'], // Optional: filter by symbols
  limit: 100,
  offset: 0,
})

Markets

// List markets for an exchange
const { markets, total } = await luzia.markets.list('binance', {
  base: 'BTC',    // Optional: filter by base currency
  quote: 'USDT',  // Optional: filter by quote currency
  active: true,   // Optional: filter by active status
  limit: 100,
  offset: 0,
})

History (OHLCV Candles)

// Get 24h of hourly candles (default)
const { candles, count } = await luzia.history.get('binance', 'BTC/USDT')

// Specify interval and limit
const { candles } = await luzia.history.get('binance', 'ETH/USDT', {
  interval: '15m',  // '1m' | '5m' | '15m' | '1h' | '1d'
  limit: 96,        // Number of candles (max: 500)
})

// Specify a time range
const { candles } = await luzia.history.get('binance', 'BTC/USDT', {
  interval: '1d',
  start: Date.now() - 30 * 24 * 60 * 60 * 1000, // 30 days ago (Unix ms)
  end: Date.now(),
})

// Each candle contains:
for (const candle of candles) {
  console.log({
    timestamp: candle.timestamp, // Candle open time (RFC 3339 string)
    open: candle.open,
    high: candle.high,
    low: candle.low,
    close: candle.close,
    volume: candle.volume,       // Base currency volume
    quoteVolume: candle.quoteVolume,
    trades: candle.trades,       // Number of trades in interval
  })
}

Lookback limits by tier:

Tier Max Lookback
Free 30 days
Pro 90 days

WebSocket (Real-Time Updates)

Stream live ticker updates over WebSocket. Requires a Pro plan or higher.

Quick Start

import { Luzia } from '@luziadev/sdk'

const luzia = new Luzia({ apiKey: 'lz_your_api_key' })
const ws = luzia.createWebSocket()

ws.on('connected', (info) => {
  console.log(`Connected (${info.tier}), max subscriptions: ${info.limits.maxSubscriptions}`)
  ws.subscribe(['ticker:binance:BTC/USDT', 'ticker:coinbase:ETH/USDT'])
})

ws.on('ticker', (data) => {
  console.log(`${data.exchange} ${data.symbol}: $${data.data.last}`)
})

ws.on('error', (err) => {
  console.error(`WebSocket error [${err.code}]: ${err.message}`)
})

ws.connect()

Channel Format

  • ticker:{exchange}:{symbol} β€” specific pair (e.g., ticker:binance:BTC/USDT)
  • ticker:{exchange} β€” all tickers from an exchange (e.g., ticker:binance)

Subscribing and Unsubscribing

// Subscribe to channels (can be called before or after connect)
ws.subscribe(['ticker:binance:BTC/USDT', 'ticker:kraken:ETH/USDT'])

// Unsubscribe from channels
ws.unsubscribe(['ticker:binance:BTC/USDT'])

// Check active subscriptions
console.log(ws.subscriptions) // ReadonlySet<string>

Connection Options

const ws = luzia.createWebSocket({
  autoReconnect: true,        // Auto-reconnect on disconnection (default: true)
  maxReconnectAttempts: 10,   // Max attempts, 0 = infinite (default: 10)
  reconnectDelayMs: 1000,     // Initial reconnect delay (default: 1000ms)
  maxReconnectDelayMs: 30000, // Max reconnect delay (default: 30000ms)
  heartbeatIntervalMs: 30000, // Heartbeat interval, 0 = disabled (default: 30000ms)
})

Events

Event Payload Description
connected { tier, limits } Connection established, server ready
ticker { exchange, symbol, data, timestamp } Price update received
subscribed { channel } Channel subscription confirmed
unsubscribed { channel } Channel unsubscription confirmed
error { code, message } Error from server or connection
disconnected { code, reason } Connection closed
reconnecting { attempt, delayMs } Reconnect attempt starting

Connection State

console.log(ws.state) // 'disconnected' | 'connecting' | 'connected' | 'reconnecting'

Disconnecting

// Gracefully close and disable auto-reconnect
ws.disconnect()

Connection Limits

Tier Connections Subscriptions / Connection
Free Not available β€”
Pro 5 50
Enterprise 25 500

Balance Management

Check your balance, view transaction history, discover pricing, and top up your account.

Check Balance

const balance = await luzia.billing.getBalance()
console.log(`Balance: $${balance.balance_usd}`)
console.log(`Lifetime spent: $${balance.lifetime_spent_usd}`)

View Pricing

// Public endpoint (no auth required)
const pricing = await luzia.billing.getPricing()
for (const entry of pricing.rest) {
  console.log(`${entry.endpoint}: $${entry.cost_usd}/${entry.unit}`)
}

Transaction History

const { transactions, total } = await luzia.billing.getTransactions({
  page: 1,
  limit: 20,
  type: 'debit', // Optional: 'debit' | 'credit' | 'refund' | 'bonus'
})

for (const tx of transactions) {
  console.log(`${tx.type}: ${tx.amount_usd} - ${tx.description}`)
}

Top Up

// Initiate a top-up ($5, $10, $25, $50, or $100)
const { checkout_url } = await luzia.billing.topUp(1000) // $10.00
// Redirect user to checkout_url to complete payment

Balance from Response Headers

Every authenticated API response includes balance information in headers. Access it via balanceInfo:

await luzia.tickers.get('binance', 'BTC/USDT')

const info = luzia.balanceInfo
if (info) {
  console.log(`Remaining: $${info.balance}`)
  console.log(`Last request cost: $${info.cost}`)
}

Handling Insufficient Balance

import { InsufficientBalanceError } from '@luziadev/sdk'

try {
  await luzia.tickers.get('binance', 'BTC/USDT')
} catch (error) {
  if (error instanceof InsufficientBalanceError) {
    console.log(`Balance: $${error.balance}`)
    console.log(`Top up at: ${error.topUpUrl}`)
  }
}

Error Handling

The SDK uses a single LuziaError class with a code property to distinguish error types:

import { Luzia, LuziaError } from '@luziadev/sdk'

try {
  const ticker = await luzia.tickers.get('invalid', 'BTC/USDT')
} catch (error) {
  if (error instanceof LuziaError) {
    switch (error.code) {
      case 'auth':
        console.log('Invalid API key')
        break
      case 'insufficient_balance':
        console.log(`Balance too low: $${error.balanceUsd}. Top up: ${error.topUpUrl}`)
        break
      case 'rate_limit':
        console.log(`Rate limited. Retry after ${error.retryAfter} seconds`)
        console.log(`Limit info:`, error.rateLimitInfo)
        break
      case 'not_found':
        console.log('Resource not found')
        break
      case 'validation':
        console.log('Invalid request parameters:', error.details)
        break
      case 'server':
        console.log('Server error (exchange may be temporarily unavailable)')
        break
      case 'network':
        console.log('Network error:', error.message)
        break
      case 'timeout':
        console.log(`Request timed out after ${error.timeoutMs}ms`)
        break
    }
  }
}

Checking Error Types

import { isLuziaError, isRetryableError } from '@luziadev/sdk'

if (isLuziaError(error)) {
  console.log(`Luzia error: ${error.message}`)
}

if (isRetryableError(error)) {
  console.log('This error can be retried')
}

Rate Limit Information

Access rate limit information from the most recent request:

const ticker = await luzia.tickers.get('binance', 'BTC/USDT')

const info = luzia.rateLimitInfo
if (info) {
  console.log(`Requests remaining: ${info.remaining}/${info.limit}`)
  console.log(`Resets at: ${new Date(info.reset * 1000)}`)

  // Free tier also has daily limits
  if (info.dailyLimit) {
    console.log(`Daily remaining: ${info.dailyRemaining}/${info.dailyLimit}`)
  }
}

Automatic Retries

The SDK automatically retries requests on:

  • Rate limit errors (429) - respects Retry-After header
  • Timeout errors (408)
  • Server errors (500, 502, 503, 504)
  • Network errors

Non-retryable errors (400, 401, 402, 403, 404) are thrown immediately.

Custom Retry Handling

import { withRetry } from '@luziadev/sdk'

// Use the retry utility directly
const result = await withRetry(
  () => luzia.tickers.get('binance', 'BTC/USDT'),
  { maxRetries: 5 },
  (context) => {
    console.log(`Retry attempt ${context.attempt + 1}/${context.maxRetries}`)
  }
)

Types

All types are exported for use in your application:

import type {
  // REST API
  Exchange,
  ExchangeStatus,
  Market,
  Ticker,
  OHLCVCandle,
  OHLCVResponse,
  CandleInterval,
  GetHistoryOptions,
  RateLimitInfo,
  LuziaOptions,
  RetryOptions,
  // Billing
  BalanceInfo,
  BalanceResponse,
  BalanceTransaction,
  PricingResponse,
  TopUpResponse,
  TopUpAmount,
  TransactionsResponse,
  TransactionType,
  ListTransactionsOptions,
  // WebSocket
  WebSocketOptions,
  WSTickerData,
  WSConnectedData,
  WSErrorData,
  WSEventMap,
  WSConnectionState,
} from '@luziadev/sdk'

Development

# Install dependencies
bun install

# Generate types from OpenAPI spec
bun run generate

# Type check
bun run typecheck

# Run tests
bun test

Links

License

MIT

About

Luzia πŸŒ… Crypto Typescript SDK

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors