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 >
Stacks wallet address (mainnet starts with SP, testnet starts with ST)
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 >
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 >
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 >
Array of transaction objects (max 10, most recent first)
Returns [] on error Shortened ID for display (e.g., “0x1234ab…89ef”)
Direct link to Hiro Explorer for this transaction
Transaction type (e.g., “token_transfer”, “contract_call”)
Transaction status (“success”, “pending”, “failed”)
Amount transferred (e.g., “10.0000 STX”) or ”—” if not applicable
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 >
Current STX price in USD (e.g., 2.85)
Returns cached value or fallback (2.85) on error
Price Fetching Strategy
Check Cache
First checks localStorage for recently cached price (shared with PriceTicker component) Valid for: 1 hour
CryptoCompare API
If cache miss, tries CryptoCompare API (better CORS support) https://min-api.cryptocompare.com/data/price?fsym=STX&tsyms=USD
CoinGecko API
Falls back to CoinGecko if CryptoCompare fails https://api.coingecko.com/api/v3/simple/price?ids=blockstack&vs_currencies=usd
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 >
Complete portfolio data object sBTC balance (8 decimals)
Recent transaction history (max 10)
Total portfolio value in USD (2 decimals)
Example
Basic Usage
React Component
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
Address prefix: ST
API base: https://api.testnet.hiro.so
Explorer: https://explorer.hiro.so?chain=testnet
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.
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 ;
}