Skip to main content

Overview

The Stacks API service provides functions to interact with the Hiro Stacks API for fetching real-time blockchain data. All functions automatically detect network (testnet/mainnet) based on address prefix. Source: src/services/stacksApi.js

Functions

getSTXBalance

Fetch a user’s STX token balance.
async function getSTXBalance(address: string): Promise<string>
address
string
required
Stacks wallet address (mainnet starts with SP, testnet starts with ST)
balance
string
STX balance formatted to 4 decimal places (e.g., “100.0000”) Returns "0.0000" on error

Example

import { getSTXBalance } from './services/stacksApi';

const balance = await getSTXBalance('SP2H8PY27SEZ03MWRKS5XABZYQN17ETGQS3527SA5');
console.log('STX Balance:', balance); // "100.0000"
Balance is returned in STX units (converted from microstacks). 1 STX = 1,000,000 microstacks.

getSBTCBalance

Fetch a user’s sBTC (synthetic Bitcoin) balance.
async function getSBTCBalance(address: string): Promise<string>
address
string
required
Stacks wallet address
balance
string
sBTC balance formatted to 8 decimal places (e.g., “0.00500000”) Returns "0.00000000" on error

Example

import { getSBTCBalance } from './services/stacksApi';

const sbtcBalance = await getSBTCBalance(address);
console.log('sBTC Balance:', sbtcBalance); // "0.00500000"

Supported Contracts

The function checks multiple sBTC contract addresses:
const sBTCContracts = [
  'SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token', // Mainnet
  'ST1F7QA2MDF17S807EPA36TSS8AMEFY4KA9TVGWXT.sbtc-token', // Testnet
];

getTokenBalances

Fetch all fungible token balances for an address.
async function getTokenBalances(address: string): Promise<object>
address
string
required
Stacks wallet address
tokens
object
Object mapping token contract IDs to balance info Returns {} (empty object) on error
{
  "SP000...token-contract": {
    balance: "1000000",
    total_sent: "0",
    total_received: "1000000"
  }
}

Example

import { getTokenBalances } from './services/stacksApi';

const tokens = await getTokenBalances(address);

for (const [contractId, info] of Object.entries(tokens)) {
  console.log(`${contractId}: ${info.balance}`);
}

getTransactionHistory

Fetch recent transaction history for an address.
async function getTransactionHistory(address: string): Promise<array>
address
string
required
Stacks wallet address
transactions
array
Array of transaction objects (max 10, most recent first) Returns [] on error
txId
string
Full transaction ID
shortTxId
string
Shortened ID for display (e.g., “0x1234ab…89ef”)
explorerUrl
string
Direct link to Hiro Explorer for this transaction
type
string
Transaction type (e.g., “token_transfer”, “contract_call”)
status
string
Transaction status (“success”, “pending”, “failed”)
amount
string
Amount transferred (e.g., “10.0000 STX”) or ”—” if not applicable
date
string
Formatted date string (e.g., “1/15/2024”)

Example

import { getTransactionHistory } from './services/stacksApi';

const txHistory = await getTransactionHistory(address);

txHistory.forEach(tx => {
  console.log(`${tx.date}: ${tx.amount} - ${tx.status}`);
  console.log(`View: ${tx.explorerUrl}`);
});

getSTXPrice

Fetch current STX price in USD with multiple fallback sources.
async function getSTXPrice(): Promise<number>
price
number
Current STX price in USD (e.g., 2.85) Returns cached value or fallback (2.85) on error

Price Fetching Strategy

1

Check Cache

First checks localStorage for recently cached price (shared with PriceTicker component)Valid for: 1 hour
2

CryptoCompare API

If cache miss, tries CryptoCompare API (better CORS support)
https://min-api.cryptocompare.com/data/price?fsym=STX&tsyms=USD
3

CoinGecko API

Falls back to CoinGecko if CryptoCompare fails
https://api.coingecko.com/api/v3/simple/price?ids=blockstack&vs_currencies=usd
4

Hard Default

Returns 2.85 if all APIs fail (reasonable fallback)

Example

import { getSTXPrice } from './services/stacksApi';

const price = await getSTXPrice();
console.log('STX Price:', price); // 2.85

// Calculate portfolio value
const stxBalance = await getSTXBalance(address);
const usdValue = (parseFloat(stxBalance) * price).toFixed(2);
console.log('Portfolio:', usdValue, 'USD');

getFullPortfolio

Fetch complete portfolio data in a single call (parallelized).
async function getFullPortfolio(address: string): Promise<object>
address
string
required
Stacks wallet address
portfolio
object
Complete portfolio data object
stxBalance
string
STX balance (4 decimals)
sbtcBalance
string
sBTC balance (8 decimals)
txHistory
array
Recent transaction history (max 10)
stxPrice
number
Current STX price in USD
totalUSD
string
Total portfolio value in USD (2 decimals)

Example

import { getFullPortfolio } from './services/stacksApi';

const portfolio = await getFullPortfolio(address);

console.log('STX:', portfolio.stxBalance);
console.log('sBTC:', portfolio.sbtcBalance);
console.log('Total USD:', portfolio.totalUSD);
console.log('Recent TXs:', portfolio.txHistory.length);
This function parallelizes all API calls using Promise.all for optimal performance.

Network Detection

All functions automatically detect the correct API endpoint:
function getApiBase(address) {
  return address?.startsWith('ST')
    ? 'https://api.testnet.hiro.so'
    : 'https://api.hiro.so';
}
Address prefix: SP
API base: https://api.hiro.so
Explorer: https://explorer.hiro.so

Error Handling

All functions gracefully handle errors:
  • Balance functions return "0" with appropriate decimal places
  • Transaction history returns empty array []
  • Price function returns cached value or 2.85 fallback
  • Token balances returns empty object {}
  • Errors are logged to console for debugging
try {
  const res = await fetch(apiUrl);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return processData(await res.json());
} catch (err) {
  console.error('API error:', err);
  return fallbackValue;
}
No exceptions are thrown - all functions return safe defaults on error.

Performance Optimization

Parallel Requests

getFullPortfolio uses Promise.all to fetch data in parallel:
const [stxBalance, sbtcBalance, txHistory, stxPrice] = await Promise.all([
  getSTXBalance(address),
  getSBTCBalance(address),
  getTransactionHistory(address),
  getSTXPrice(),
]);

Price Caching

STX price is cached in localStorage for 1 hour:
const cached = localStorage.getItem('staxiq_prices');
if (cached) {
  const { data, timestamp } = JSON.parse(cached);
  if (Date.now() - timestamp < 3600000) { // 1 hour
    return parseFloat(data.stx.usd);
  }
}

Complete Example

import {
  getSTXBalance,
  getSBTCBalance,
  getTransactionHistory,
  getSTXPrice,
  getFullPortfolio,
} from './services/stacksApi';

async function displayPortfolio(address) {
  console.log('Fetching portfolio for:', address);
  
  // Option 1: Individual calls
  const stx = await getSTXBalance(address);
  const sbtc = await getSBTCBalance(address);
  const price = await getSTXPrice();
  const txs = await getTransactionHistory(address);
  
  console.log(`STX: ${stx}`);
  console.log(`sBTC: ${sbtc}`);
  console.log(`STX Price: $${price}`);
  console.log(`Recent Transactions: ${txs.length}`);
  
  // Option 2: All-in-one (faster)
  const portfolio = await getFullPortfolio(address);
  
  console.log('Portfolio:', portfolio);
  console.log(`Total Value: $${portfolio.totalUSD}`);
}

API Rate Limits

Hiro API has rate limits:
  • Free tier: 50 requests/minute
  • Authenticated: Higher limits with API key
Implement caching and debouncing for production apps:
// Cache results for 30 seconds
let cache = {};
let lastFetch = 0;

async function getCachedPortfolio(address) {
  const now = Date.now();
  if (cache[address] && now - lastFetch < 30000) {
    return cache[address];
  }
  
  const data = await getFullPortfolio(address);
  cache[address] = data;
  lastFetch = now;
  return data;
}

Build docs developers (and LLMs) love