Skip to main content

Wallet Tracking

Learn how to track wallet activity, balances, and transactions using the Stellar Classic endpoints. This guide shows you how to build wallet monitoring tools and transaction tracking systems.

Overview

This page covers:

  • Retrieving wallet account information and balances
  • Fetching recent transactions and operations
  • Tracking claimable balances
  • Building wallet monitoring dashboards
Stellar Classic Endpoints

All endpoints in this section work with Stellar Classic blockchain data, not Soroban contracts.

Account Information

Get Wallet Account Details

import requests

def get_account_info(account_id):
"""Fetch account information and balances"""
url = f"https://api.hoops.finance/classic/accounts/{account_id}"
response = requests.get(url)
response.raise_for_status()
return response.json()

# Usage
account_id = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"
account_info = get_account_info(account_id)

print(f"Account: {account_info['account_id']}")
print(f"Sequence: {account_info['sequence']}")
print(f"Subentry Count: {account_info['subentry_count']}")

# Print balances
for balance in account_info['balances']:
asset = balance['asset_type']
if asset == 'native':
print(f"XLM Balance: {balance['balance']}")
else:
print(f"{asset} Balance: {balance['balance']} (Issuer: {balance['asset_issuer']})")
Use Case

Great for: Wallet balance displays, account verification, and balance monitoring

Response Fields Explained

FieldDescriptionExample
account_idStellar account addressGCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ
sequenceCurrent sequence number123456789
balancesArray of asset balances[{"asset_type": "native", "balance": "100.0000000"}]
subentry_countNumber of subentries5

Transaction History

Get Recent Transactions

def get_account_transactions(account_id, limit=10, order='desc'):
"""Fetch recent transactions for an account"""
url = f"https://api.hoops.finance/classic/accounts/{account_id}/transactions"
params = {
'limit': limit,
'order': order
}
response = requests.get(url, params=params)
response.raise_for_status()
return response.json()

def get_account_operations(account_id, limit=10, order='desc'):
"""Fetch recent operations for an account"""
url = f"https://api.hoops.finance/classic/accounts/{account_id}/operations"
params = {
'limit': limit,
'order': order
}
response = requests.get(url, params=params)
response.raise_for_status()
return response.json()

# Usage
account_id = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"

# Get recent transactions
transactions = get_account_transactions(account_id, limit=5)
print("=== RECENT TRANSACTIONS ===")
for tx in transactions['_embedded']['records']:
print(f"Hash: {tx['hash']}")
print(f"Ledger: {tx['ledger']}")
print(f"Operation Count: {tx['operation_count']}")
print(f"Fee Paid: {tx['fee_paid']} XLM")
print("---")

# Get recent operations
operations = get_account_operations(account_id, limit=5)
print("=== RECENT OPERATIONS ===")
for op in operations['_embedded']['records']:
print(f"Type: {op['type']}")
print(f"Transaction Hash: {op['transaction_hash']}")
print(f"Created At: {op['created_at']}")
print("---")
async function getAccountTransactions(accountId, limit = 10, order = 'desc') {
try {
const url = new URL(`https://api.hoops.finance/classic/accounts/${accountId}/transactions`);
url.searchParams.append('limit', limit);
url.searchParams.append('order', order);

const response = await fetch(url);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return response.json();
} catch (error) {
console.error('Error fetching transactions:', error.message);
throw error;
}
}

async function getAccountOperations(accountId, limit = 10, order = 'desc') {
try {
const url = new URL(`https://api.hoops.finance/classic/accounts/${accountId}/operations`);
url.searchParams.append('limit', limit);
url.searchParams.append('order', order);

const response = await fetch(url);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return response.json();
} catch (error) {
console.error('Error fetching operations:', error.message);
throw error;
}
}

// Usage
const accountId = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";

// Get recent transactions
getAccountTransactions(accountId, 5).then(transactions => {
console.log("=== RECENT TRANSACTIONS ===");
transactions._embedded.records.forEach(tx => {
console.log(`Hash: ${tx.hash}`);
console.log(`Ledger: ${tx.ledger}`);
console.log(`Operation Count: ${tx.operation_count}`);
console.log(`Fee Paid: ${tx.fee_paid} XLM`);
console.log("---");
});
});

// Get recent operations
getAccountOperations(accountId, 5).then(operations => {
console.log("=== RECENT OPERATIONS ===");
operations._embedded.records.forEach(op => {
console.log(`Type: ${op.type}`);
console.log(`Transaction Hash: ${op.transaction_hash}`);
console.log(`Created At: ${op.created_at}`);
console.log("---");
});
});
Use Case

Great for: Transaction history displays, activity feeds, and audit trails

Claimable Balances

Track Claimable Balances

def get_account_claimable_balances(account_id):
"""Fetch claimable balances for an account"""
url = f"https://api.hoops.finance/classic/accounts/{account_id}/claimable_balances"
response = requests.get(url)
response.raise_for_status()
return response.json()

def get_claimable_balance_details(balance_id):
"""Fetch details for a specific claimable balance"""
url = f"https://api.hoops.finance/classic/claimable_balances/{balance_id}"
response = requests.get(url)
response.raise_for_status()
return response.json()

# Usage
account_id = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"

# Get claimable balances
claimable_balances = get_account_claimable_balances(account_id)
print("=== CLAIMABLE BALANCES ===")
for balance in claimable_balances['_embedded']['records']:
print(f"Balance ID: {balance['id']}")
print(f"Asset: {balance['asset']}")
print(f"Amount: {balance['amount']}")
print(f"Claimants: {len(balance['claimants'])}")
print("---")
async function getAccountClaimableBalances(accountId) {
try {
const response = await fetch(`https://api.hoops.finance/classic/accounts/${accountId}/claimable_balances`);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return response.json();
} catch (error) {
console.error('Error fetching claimable balances:', error.message);
throw error;
}
}

async function getClaimableBalanceDetails(balanceId) {
try {
const response = await fetch(`https://api.hoops.finance/classic/claimable_balances/${balanceId}`);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return response.json();
} catch (error) {
console.error('Error fetching claimable balance details:', error.message);
throw error;
}
}

// Usage
const accountId = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";

getAccountClaimableBalances(accountId).then(balances => {
console.log("=== CLAIMABLE BALANCES ===");
balances._embedded.records.forEach(balance => {
console.log(`Balance ID: ${balance.id}`);
console.log(`Asset: ${balance.asset}`);
console.log(`Amount: ${balance.amount}`);
console.log(`Claimants: ${balance.claimants.length}`);
console.log("---");
});
});
Use Case

Great for: Airdrop tracking, vesting schedules, and reward distribution

Payment Tracking

Monitor Payments

def get_account_payments(account_id, limit=10):
"""Fetch payment operations for an account"""
url = f"https://api.hoops.finance/classic/accounts/{account_id}/payments"
params = {'limit': limit}
response = requests.get(url, params=params)
response.raise_for_status()
return response.json()

# Usage
account_id = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"

payments = get_account_payments(account_id, limit=5)
print("=== RECENT PAYMENTS ===")
for payment in payments['_embedded']['records']:
print(f"Type: {payment['type']}")
print(f"Amount: {payment['amount']}")
print(f"Asset: {payment['asset_type']}")
if payment['asset_type'] != 'native':
print(f"Asset Code: {payment['asset_code']}")
print(f"Asset Issuer: {payment['asset_issuer']}")
print(f"From: {payment['from']}")
print(f"To: {payment['to']}")
print("---")
async function getAccountPayments(accountId, limit = 10) {
try {
const url = new URL(`https://api.hoops.finance/classic/accounts/${accountId}/payments`);
url.searchParams.append('limit', limit);

const response = await fetch(url);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return response.json();
} catch (error) {
console.error('Error fetching payments:', error.message);
throw error;
}
}

// Usage
const accountId = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";

getAccountPayments(accountId, 5).then(payments => {
console.log("=== RECENT PAYMENTS ===");
payments._embedded.records.forEach(payment => {
console.log(`Type: ${payment.type}`);
console.log(`Amount: ${payment.amount}`);
console.log(`Asset: ${payment.asset_type}`);
if (payment.asset_type !== 'native') {
console.log(`Asset Code: ${payment.asset_code}`);
console.log(`Asset Issuer: ${payment.asset_issuer}`);
}
console.log(`From: ${payment.from}`);
console.log(`To: ${payment.to}`);
console.log("---");
});
});
Use Case

Great for: Payment tracking, transaction monitoring, and financial reporting

Building a Wallet Dashboard

Complete Wallet Monitoring System

import requests
from datetime import datetime
import json

class WalletTracker:
def __init__(self):
self.base_url = "https://api.hoops.finance"

def get_wallet_summary(self, account_id):
"""Get comprehensive wallet summary"""
try:
# Get account info
account_info = requests.get(f"{self.base_url}/classic/accounts/{account_id}").json()

# Get recent transactions
transactions = requests.get(f"{self.base_url}/classic/accounts/{account_id}/transactions?limit=5").json()

# Get claimable balances
claimable_balances = requests.get(f"{self.base_url}/classic/accounts/{account_id}/claimable_balances").json()

return {
'account': account_info,
'recent_transactions': transactions['_embedded']['records'],
'claimable_balances': claimable_balances['_embedded']['records']
}
except Exception as e:
print(f"Error fetching wallet data: {e}")
return None

def format_balance(self, balance):
"""Format balance for display"""
if balance['asset_type'] == 'native':
return f"{float(balance['balance']):.7f} XLM"
else:
return f"{balance['balance']} {balance['asset_code']}"

def display_wallet_summary(self, account_id):
"""Display formatted wallet summary"""
data = self.get_wallet_summary(account_id)
if not data:
return

print("=== WALLET SUMMARY ===")
print(f"Account: {data['account']['account_id']}")
print(f"Sequence: {data['account']['sequence']}")
print()

print("=== BALANCES ===")
for balance in data['account']['balances']:
print(f" {self.format_balance(balance)}")
print()

print("=== RECENT TRANSACTIONS ===")
for tx in data['recent_transactions']:
print(f" Hash: {tx['hash'][:16]}...")
print(f" Ledger: {tx['ledger']}")
print(f" Operations: {tx['operation_count']}")
print(f" Fee: {tx['fee_paid']} XLM")
print()

print("=== CLAIMABLE BALANCES ===")
if data['claimable_balances']:
for balance in data['claimable_balances']:
print(f" ID: {balance['id'][:16]}...")
print(f" Asset: {balance['asset']}")
print(f" Amount: {balance['amount']}")
else:
print(" No claimable balances")

# Usage
tracker = WalletTracker()
account_id = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"
tracker.display_wallet_summary(account_id)
class WalletTracker {
constructor() {
this.baseUrl = 'https://api.hoops.finance';
}

async getWalletSummary(accountId) {
try {
const [accountInfo, transactions, claimableBalances] = await Promise.all([
fetch(`${this.baseUrl}/classic/accounts/${accountId}`),
fetch(`${this.baseUrl}/classic/accounts/${accountId}/transactions?limit=5`),
fetch(`${this.baseUrl}/classic/accounts/${accountId}/claimable_balances`)
]);

if (!accountInfo.ok || !transactions.ok || !claimableBalances.ok) {
throw new Error(`HTTP error! status: ${accountInfo.status}, ${transactions.status}, or ${claimableBalances.status}`);
}

const [accountData, transactionsData, claimableBalancesData] = await Promise.all([
accountInfo.json(),
transactions.json(),
claimableBalances.json()
]);

return {
account: accountData,
recentTransactions: transactionsData._embedded.records,
claimableBalances: claimableBalancesData._embedded.records
};
} catch (error) {
console.error('Error fetching wallet data:', error.message);
return null;
}
}

formatBalance(balance) {
if (balance.asset_type === 'native') {
return `${parseFloat(balance.balance).toFixed(7)} XLM`;
} else {
return `${balance.balance} ${balance.asset_code}`;
}
}

async displayWalletSummary(accountId) {
const data = await this.getWalletSummary(accountId);
if (!data) return;

console.log('=== WALLET SUMMARY ===');
console.log(`Account: ${data.account.account_id}`);
console.log(`Sequence: ${data.account.sequence}`);
console.log();

console.log('=== BALANCES ===');
data.account.balances.forEach(balance => {
console.log(` ${this.formatBalance(balance)}`);
});
console.log();

console.log('=== RECENT TRANSACTIONS ===');
data.recentTransactions.forEach(tx => {
console.log(` Hash: ${tx.hash.substring(0, 16)}...`);
console.log(` Ledger: ${tx.ledger}`);
console.log(` Operations: ${tx.operation_count}`);
console.log(` Fee: ${tx.fee_paid} XLM`);
console.log();
});

console.log('=== CLAIMABLE BALANCES ===');
if (data.claimableBalances.length > 0) {
data.claimableBalances.forEach(balance => {
console.log(` ID: ${balance.id.substring(0, 16)}...`);
console.log(` Asset: ${balance.asset}`);
console.log(` Amount: ${balance.amount}`);
});
} else {
console.log(' No claimable balances');
}
}
}

// Usage
const tracker = new WalletTracker();
const accountId = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ";
tracker.displayWalletSummary(accountId);

Network Considerations

Testnet vs Mainnet

Network Selection

Always verify you're using the correct network (testnet vs mainnet) for your use case. Account addresses look the same but operate on different networks.

Testnet Account Example:

GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ

Mainnet Account Example:

GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ

Error Handling

def safe_get_account_info(account_id):
"""Safely fetch account info with error handling"""
try:
response = requests.get(f"https://api.hoops.finance/classic/accounts/{account_id}")
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
print(f"Account {account_id} not found")
else:
print(f"HTTP Error: {e}")
return None
except requests.exceptions.RequestException as e:
print(f"Request Error: {e}")
return None

Next Steps

Rate Limiting

Remember to implement proper rate limiting in production applications. The API allows 120 requests per minute.