Token Data
Learn how to fetch and manage token metadata for building UI components like token selectors, dropdowns, and list views. This guide shows you how to work with token information efficiently.
Overview
This page covers:
- Fetching the complete token list
- Getting individual token details
- Finding associated pairs for tokens
- Building token selection components
- Caching and updating token data
Getting All Tokens
Fetch Complete Token List
- Python
- JavaScript
- TypeScript
- cURL
- Go
- Rust
- Java
- Shell
import requests
import json
def get_all_tokens():
"""Fetch all available tokens"""
url = "https://api.hoops.finance/tokens"
response = requests.get(url)
response.raise_for_status()
return response.json()
def get_token_details(token_address):
"""Fetch detailed information for a specific token"""
url = f"https://api.hoops.finance/tokens/{token_address}"
response = requests.get(url)
response.raise_for_status()
return response.json()
# Usage
tokens = get_all_tokens()
print(f"Total tokens: {len(tokens['tokens'])}")
# Display first 5 tokens
for token in tokens['tokens'][:5]:
print(f"Symbol: {token['symbol']}")
print(f"Name: {token['name']}")
print(f"Address: {token['address']}")
print(f"Decimals: {token['decimals']}")
print("---")
async function getAllTokens() {
try {
const response = await fetch('https://api.hoops.finance/tokens');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
} catch (error) {
console.error('Error fetching tokens:', error.message);
throw error;
}
}
async function getTokenDetails(tokenAddress) {
try {
const response = await fetch(`https://api.hoops.finance/tokens/${tokenAddress}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
} catch (error) {
console.error('Error fetching token details:', error.message);
throw error;
}
}
// Usage
getAllTokens().then(data => {
console.log(`Total tokens: ${data.tokens.length}`);
// Display first 5 tokens
data.tokens.slice(0, 5).forEach(token => {
console.log(`Symbol: ${token.symbol}`);
console.log(`Name: ${token.name}`);
console.log(`Address: ${token.address}`);
console.log(`Decimals: ${token.decimals}`);
console.log('---');
});
});
interface Token {
symbol: string;
name: string;
address: string;
decimals: number;
totalSupply?: string;
imageUrl?: string;
}
interface TokenResponse {
tokens: Token[];
}
async function getAllTokens(): Promise<TokenResponse> {
try {
const response = await fetch('https://api.hoops.finance/tokens');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
} catch (error) {
console.error('Error fetching tokens:', error);
throw error;
}
}
async function getTokenDetails(tokenAddress: string): Promise<Token> {
try {
const response = await fetch(`https://api.hoops.finance/tokens/${tokenAddress}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
} catch (error) {
console.error('Error fetching token details:', error);
throw error;
}
}
// Usage
getAllTokens().then(data => {
console.log(`Total tokens: ${data.tokens.length}`);
data.tokens.slice(0, 5).forEach(token => {
console.log(`Symbol: ${token.symbol}`);
console.log(`Name: ${token.name}`);
console.log(`Address: ${token.address}`);
console.log(`Decimals: ${token.decimals}`);
console.log('---');
});
});
# Get all tokens
curl -s "https://api.hoops.finance/tokens" | jq '.'
# Get token count
TOKEN_COUNT=$(curl -s "https://api.hoops.finance/tokens" | jq '.tokens | length')
echo "Total tokens: ${TOKEN_COUNT}"
# Get first 5 tokens
curl -s "https://api.hoops.finance/tokens" | jq '.tokens[0:5][] | "Symbol: \(.symbol), Name: \(.name), Address: \(.address), Decimals: \(.decimals)"'
# Get specific token details
TOKEN_ADDRESS="CAB6MICC2WKRT372U3FRPKGGVB5R3FDJSMWJL5XK6R3XWMJUCA4RJMXU"
curl -s "https://api.hoops.finance/tokens/${TOKEN_ADDRESS}" | jq '.'
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type Token struct {
Symbol string `json:"symbol"`
Name string `json:"name"`
Address string `json:"address"`
Decimals int `json:"decimals"`
TotalSupply string `json:"totalSupply,omitempty"`
ImageURL string `json:"imageUrl,omitempty"`
}
type TokenResponse struct {
Tokens []Token `json:"tokens"`
}
func getAllTokens() (*TokenResponse, error) {
resp, err := http.Get("https://api.hoops.finance/tokens")
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var tokenResponse TokenResponse
err = json.Unmarshal(body, &tokenResponse)
return &tokenResponse, err
}
func getTokenDetails(tokenAddress string) (*Token, error) {
url := fmt.Sprintf("https://api.hoops.finance/tokens/%s", tokenAddress)
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var token Token
err = json.Unmarshal(body, &token)
return &token, err
}
func main() {
tokens, err := getAllTokens()
if err != nil {
panic(err)
}
fmt.Printf("Total tokens: %d\n", len(tokens.Tokens))
// Display first 5 tokens
for i, token := range tokens.Tokens {
if i >= 5 {
break
}
fmt.Printf("Symbol: %s\n", token.Symbol)
fmt.Printf("Name: %s\n", token.Name)
fmt.Printf("Address: %s\n", token.Address)
fmt.Printf("Decimals: %d\n", token.Decimals)
fmt.Println("---")
}
}
use reqwest;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Token {
symbol: String,
name: String,
address: String,
decimals: i32,
total_supply: Option<String>,
image_url: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
struct TokenResponse {
tokens: Vec<Token>,
}
async fn get_all_tokens() -> Result<TokenResponse, Box<dyn std::error::Error>> {
let response = reqwest::get("https://api.hoops.finance/tokens").await?;
let token_response: TokenResponse = response.json().await?;
Ok(token_response)
}
async fn get_token_details(token_address: &str) -> Result<Token, Box<dyn std::error::Error>> {
let url = format!("https://api.hoops.finance/tokens/{}", token_address);
let response = reqwest::get(&url).await?;
let token: Token = response.json().await?;
Ok(token)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let tokens = get_all_tokens().await?;
println!("Total tokens: {}", tokens.tokens.len());
// Display first 5 tokens
for token in tokens.tokens.iter().take(5) {
println!("Symbol: {}", token.symbol);
println!("Name: {}", token.name);
println!("Address: {}", token.address);
println!("Decimals: {}", token.decimals);
println!("---");
}
Ok(())
}
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.util.List;
public class Token {
private String symbol;
private String name;
private String address;
private int decimals;
@JsonProperty("totalSupply")
private String totalSupply;
@JsonProperty("imageUrl")
private String imageUrl;
// Getters and setters
public String getSymbol() { return symbol; }
public void setSymbol(String symbol) { this.symbol = symbol; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
public int getDecimals() { return decimals; }
public void setDecimals(int decimals) { this.decimals = decimals; }
public String getTotalSupply() { return totalSupply; }
public void setTotalSupply(String totalSupply) { this.totalSupply = totalSupply; }
public String getImageUrl() { return imageUrl; }
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
}
public class TokenResponse {
private List<Token> tokens;
public List<Token> getTokens() { return tokens; }
public void setTokens(List<Token> tokens) { this.tokens = tokens; }
}
public class HoopsApiClient {
private static final String BASE_URL = "https://api.hoops.finance";
private final HttpClient client = HttpClient.newHttpClient();
private final ObjectMapper mapper = new ObjectMapper();
public TokenResponse getAllTokens() throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/tokens"))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return mapper.readValue(response.body(), TokenResponse.class);
}
public Token getTokenDetails(String tokenAddress) throws Exception {
String url = String.format("%s/tokens/%s", BASE_URL, tokenAddress);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
return mapper.readValue(response.body(), Token.class);
}
public static void main(String[] args) throws Exception {
HoopsApiClient client = new HoopsApiClient();
TokenResponse tokenResponse = client.getAllTokens();
System.out.printf("Total tokens: %d%n", tokenResponse.getTokens().size());
// Display first 5 tokens
tokenResponse.getTokens().stream().limit(5).forEach(token -> {
System.out.printf("Symbol: %s%n", token.getSymbol());
System.out.printf("Name: %s%n", token.getName());
System.out.printf("Address: %s%n", token.getAddress());
System.out.printf("Decimals: %d%n", token.getDecimals());
System.out.println("---");
});
}
}
#!/bin/bash
BASE_URL="https://api.hoops.finance"
get_all_tokens() {
curl -s "${BASE_URL}/tokens" | jq '.'
}
get_token_details() {
local token_address=$1
curl -s "${BASE_URL}/tokens/${token_address}" | jq '.'
}
# Usage
tokens=$(get_all_tokens)
token_count=$(echo "$tokens" | jq '.tokens | length')
echo "Total tokens: ${token_count}"
# Display first 5 tokens
echo "$tokens" | jq -r '.tokens[0:5][] | "Symbol: \(.symbol), Name: \(.name), Address: \(.address), Decimals: \(.decimals)"'
# Get specific token details
TOKEN_ADDRESS="CAB6MICC2WKRT372U3FRPKGGVB5R3FDJSMWJL5XK6R3XWMJUCA4RJMXU"
token_details=$(get_token_details "$TOKEN_ADDRESS")
echo "$token_details" | jq '.'
Use Case
Great for: Token dropdowns, search functionality, and token list displays
Response Fields Explained
Field | Description | Example |
---|---|---|
symbol | Token symbol/ticker | XLM , USDC , BTC |
name | Full token name | Stellar Lumens , USD Coin |
address | Token contract address | CAB6MICC2WKRT372U3FRPKGGVB5R3FDJSMWJL5XK6R3XWMJUCA4RJMXU |
decimals | Number of decimal places | 7 , 6 , 8 |
totalSupply | Total token supply | 1000000000000000 |
imageUrl | Token logo URL | https://example.com/token.png |
Individual Token Details
Get Specific Token Information
def get_token_with_pairs(token_address):
"""Get token details and its associated pairs"""
# Get token details
token_details = get_token_details(token_address)
# Get pairs for this token
pairs_url = f"https://api.hoops.finance/tokens/{token_address}/pairs"
pairs_response = requests.get(pairs_url)
pairs_response.raise_for_status()
pairs_data = pairs_response.json()
return {
'token': token_details,
'pairs': pairs_data['pairs']
}
# Usage
token_address = "CAB6MICC2WKRT372U3FRPKGGVB5R3FDJSMWJL5XK6R3XWMJUCA4RJMXU"
token_data = get_token_with_pairs(token_address)
print(f"Token: {token_data['token']['name']} ({token_data['token']['symbol']})")
print(f"Address: {token_data['token']['address']}")
print(f"Decimals: {token_data['token']['decimals']}")
print(f"Total Supply: {token_data['token']['totalSupply']}")
print(f"Associated Pairs: {len(token_data['pairs'])}")
# Show some pairs
for pair in token_data['pairs'][:3]:
print(f" - {pair['token0Symbol']}/{pair['token1Symbol']} (TVL: ${float(pair['tvl']):,.2f})")
async function getTokenWithPairs(tokenAddress) {
try {
const [tokenResponse, pairsResponse] = await Promise.all([
fetch(`https://api.hoops.finance/tokens/${tokenAddress}`),
fetch(`https://api.hoops.finance/tokens/${tokenAddress}/pairs`)
]);
if (!tokenResponse.ok || !pairsResponse.ok) {
throw new Error(`HTTP error! status: ${tokenResponse.status} or ${pairsResponse.status}`);
}
const [tokenData, pairsData] = await Promise.all([
tokenResponse.json(),
pairsResponse.json()
]);
return {
token: tokenData,
pairs: pairsData.pairs
};
} catch (error) {
console.error('Error fetching token data:', error.message);
throw error;
}
}
// Usage
const tokenAddress = "CAB6MICC2WKRT372U3FRPKGGVB5R3FDJSMWJL5XK6R3XWMJUCA4RJMXU";
getTokenWithPairs(tokenAddress).then(data => {
console.log(`Token: ${data.token.name} (${data.token.symbol})`);
console.log(`Address: ${data.token.address}`);
console.log(`Decimals: ${data.token.decimals}`);
console.log(`Total Supply: ${data.token.totalSupply}`);
console.log(`Associated Pairs: ${data.pairs.length}`);
// Show some pairs
data.pairs.slice(0, 3).forEach(pair => {
console.log(` - ${pair.token0Symbol}/${pair.token1Symbol} (TVL: $${parseFloat(pair.tvl).toLocaleString()})`);
});
});
Use Case
Great for: Token detail pages, pair discovery, and token analysis
Building Token Selection Components
Python Token Selector
class TokenSelector:
def __init__(self):
self.tokens = {}
self.load_tokens()
def load_tokens(self):
"""Load all tokens into memory"""
try:
response = requests.get("https://api.hoops.finance/tokens")
data = response.json()
# Create lookup dictionaries
for token in data['tokens']:
self.tokens[token['address']] = token
self.tokens[token['symbol'].lower()] = token
self.tokens[token['name'].lower()] = token
print(f"Loaded {len(data['tokens'])} tokens")
except Exception as e:
print(f"Error loading tokens: {e}")
def search_tokens(self, query, limit=10):
"""Search tokens by symbol, name, or address"""
query = query.lower()
results = []
for token in self.tokens.values():
if (query in token['symbol'].lower() or
query in token['name'].lower() or
query in token['address'].lower()):
results.append(token)
if len(results) >= limit:
break
return results
def get_token_by_symbol(self, symbol):
"""Get token by symbol"""
return self.tokens.get(symbol.lower())
def get_token_by_address(self, address):
"""Get token by address"""
return self.tokens.get(address)
def get_popular_tokens(self, limit=10):
"""Get popular tokens (XLM, USDC, etc.)"""
popular_symbols = ['XLM', 'USDC', 'BTC', 'ETH', 'USDT']
popular_tokens = []
for symbol in popular_symbols:
token = self.get_token_by_symbol(symbol)
if token:
popular_tokens.append(token)
return popular_tokens[:limit]
# Usage
selector = TokenSelector()
# Search for tokens
results = selector.search_tokens("USDC")
for token in results:
print(f"{token['symbol']} - {token['name']}")
# Get popular tokens
popular = selector.get_popular_tokens()
print("\nPopular tokens:")
for token in popular:
print(f" {token['symbol']}: {token['name']}")
JavaScript Token Selector
class TokenSelector {
constructor() {
this.tokens = {};
this.loadTokens();
}
async loadTokens() {
try {
const response = await fetch('https://api.hoops.finance/tokens');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// Create lookup objects
data.tokens.forEach(token => {
this.tokens[token.address] = token;
this.tokens[token.symbol.toLowerCase()] = token;
this.tokens[token.name.toLowerCase()] = token;
});
console.log(`Loaded ${data.tokens.length} tokens`);
} catch (error) {
console.error('Error loading tokens:', error.message);
}
}
searchTokens(query, limit = 10) {
const queryLower = query.toLowerCase();
const results = [];
Object.values(this.tokens).forEach(token => {
if (token.symbol.toLowerCase().includes(queryLower) ||
token.name.toLowerCase().includes(queryLower) ||
token.address.toLowerCase().includes(queryLower)) {
results.push(token);
}
});
return results.slice(0, limit);
}
getTokenBySymbol(symbol) {
return this.tokens[symbol.toLowerCase()];
}
getTokenByAddress(address) {
return this.tokens[address];
}
getPopularTokens(limit = 10) {
const popularSymbols = ['XLM', 'USDC', 'BTC', 'ETH', 'USDT'];
const popularTokens = [];
popularSymbols.forEach(symbol => {
const token = this.getTokenBySymbol(symbol);
if (token) {
popularTokens.push(token);
}
});
return popularTokens.slice(0, limit);
}
}
// Usage
const selector = new TokenSelector();
// Wait for tokens to load, then search
setTimeout(() => {
const results = selector.searchTokens('USDC');
results.forEach(token => {
console.log(`${token.symbol} - ${token.name}`);
});
const popular = selector.getPopularTokens();
console.log('\nPopular tokens:');
popular.forEach(token => {
console.log(` ${token.symbol}: ${token.name}`);
});
}, 1000);
Use Case
Great for: Token search interfaces, autocomplete components, and token selection dropdowns
Token Data Caching
Python Caching Implementation
import time
import json
from datetime import datetime, timedelta
class TokenCache:
def __init__(self, cache_duration=3600): # 1 hour default
self.cache_duration = cache_duration
self.cache = {}
self.last_update = None
def is_cache_valid(self):
"""Check if cache is still valid"""
if not self.last_update:
return False
return datetime.now() - self.last_update < timedelta(seconds=self.cache_duration)
def update_cache(self):
"""Update the token cache"""
try:
response = requests.get("https://api.hoops.finance/tokens")
data = response.json()
self.cache = {
'tokens': data['tokens'],
'timestamp': datetime.now().isoformat()
}
self.last_update = datetime.now()
print(f"Cache updated with {len(data['tokens'])} tokens")
return True
except Exception as e:
print(f"Error updating cache: {e}")
return False
def get_tokens(self, force_update=False):
"""Get tokens, updating cache if necessary"""
if force_update or not self.is_cache_valid():
self.update_cache()
return self.cache.get('tokens', [])
def save_cache_to_file(self, filename='token_cache.json'):
"""Save cache to file"""
with open(filename, 'w') as f:
json.dump(self.cache, f)
def load_cache_from_file(self, filename='token_cache.json'):
"""Load cache from file"""
try:
with open(filename, 'r') as f:
self.cache = json.load(f)
self.last_update = datetime.fromisoformat(self.cache['timestamp'])
print(f"Loaded {len(self.cache['tokens'])} tokens from cache")
except FileNotFoundError:
print("No cache file found")
except Exception as e:
print(f"Error loading cache: {e}")
# Usage
cache = TokenCache(cache_duration=1800) # 30 minutes
cache.load_cache_from_file()
# Get tokens (will use cache if valid)
tokens = cache.get_tokens()
print(f"Available tokens: {len(tokens)}")
# Force update
tokens = cache.get_tokens(force_update=True)
# Save cache
cache.save_cache_to_file()
JavaScript Caching Implementation
class TokenCache {
constructor(cacheDuration = 3600) { // 1 hour default
this.cacheDuration = cacheDuration;
this.cache = {};
this.lastUpdate = null;
}
isCacheValid() {
if (!this.lastUpdate) return false;
const now = new Date();
const timeDiff = (now - this.lastUpdate) / 1000; // seconds
return timeDiff < this.cacheDuration;
}
async updateCache() {
try {
const response = await fetch('https://api.hoops.finance/tokens');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
this.cache = {
tokens: data.tokens,
timestamp: new Date().toISOString()
};
this.lastUpdate = new Date();
console.log(`Cache updated with ${data.tokens.length} tokens`);
return true;
} catch (error) {
console.error('Error updating cache:', error.message);
return false;
}
}
async getTokens(forceUpdate = false) {
if (forceUpdate || !this.isCacheValid()) {
await this.updateCache();
}
return this.cache.tokens || [];
}
saveCacheToLocalStorage() {
try {
localStorage.setItem('tokenCache', JSON.stringify(this.cache));
console.log('Cache saved to localStorage');
} catch (error) {
console.error('Error saving cache:', error.message);
}
}
loadCacheFromLocalStorage() {
try {
const cached = localStorage.getItem('tokenCache');
if (cached) {
this.cache = JSON.parse(cached);
this.lastUpdate = new Date(this.cache.timestamp);
console.log(`Loaded ${this.cache.tokens.length} tokens from cache`);
}
} catch (error) {
console.error('Error loading cache:', error.message);
}
}
}
// Usage
const cache = new TokenCache(1800); // 30 minutes
cache.loadCacheFromLocalStorage();
// Get tokens (will use cache if valid)
cache.getTokens().then(tokens => {
console.log(`Available tokens: ${tokens.length}`);
});
// Force update
cache.getTokens(true).then(tokens => {
console.log(`Updated tokens: ${tokens.length}`);
cache.saveCacheToLocalStorage();
});
Token Image URLs
Working with Token Images
def get_token_image_url(token_address):
"""Get token image URL if available"""
token_details = get_token_details(token_address)
return token_details.get('imageUrl')
def display_token_with_image(token_address):
"""Display token info with image URL"""
token = get_token_details(token_address)
print(f"Token: {token['name']} ({token['symbol']})")
print(f"Address: {token['address']}")
if token.get('imageUrl'):
print(f"Image: {token['imageUrl']}")
else:
print("No image available")
# For web applications, you might use:
# <img src="{token['imageUrl']}" alt="{token['name']}" />
# Usage
token_address = "CAB6MICC2WKRT372U3FRPKGGVB5R3FDJSMWJL5XK6R3XWMJUCA4RJMXU"
display_token_with_image(token_address)
async function getTokenImageUrl(tokenAddress) {
try {
const response = await fetch(`https://api.hoops.finance/tokens/${tokenAddress}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const token = await response.json();
return token.imageUrl;
} catch (error) {
console.error('Error fetching token image:', error.message);
return null;
}
}
async function displayTokenWithImage(tokenAddress) {
try {
const response = await fetch(`https://api.hoops.finance/tokens/${tokenAddress}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const token = await response.json();
console.log(`Token: ${token.name} (${token.symbol})`);
console.log(`Address: ${token.address}`);
if (token.imageUrl) {
console.log(`Image: ${token.imageUrl}`);
} else {
console.log('No image available');
}
// For web applications:
// <img src={token.imageUrl} alt={token.name} />
} catch (error) {
console.error('Error:', error.message);
}
}
// Usage
const tokenAddress = "CAB6MICC2WKRT372U3FRPKGGVB5R3FDJSMWJL5XK6R3XWMJUCA4RJMXU";
displayTokenWithImage(tokenAddress);
Next Steps
- Combine with Analytics Dashboard to show token performance metrics
- Use Liquidity Monitoring to track token liquidity across pairs
- Integrate with Wallet Tracking to display token balances
Rate Limiting
Remember to implement proper rate limiting in production applications. The API allows 120 requests per minute.
Caching Best Practices
- Cache token data for 30-60 minutes to reduce API calls
- Implement fallback mechanisms for when cache is stale
- Consider using localStorage (browser) or file system (server) for persistence