From stellar-dev
Querying Stellar chain data via Stellar RPC (preferred) and Horizon (legacy). Covers methods, endpoints, streaming, pagination, historical queries, Hubble/Galexie, and migration. Use for reading balances, transactions, operations, events, or building indexers.
How this skill is triggered — by the user, by Claude, or both
Slash command
/stellar-dev:data [data task][data task]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
API access for reading chain state. Stellar RPC is the preferred entry point for new projects; Horizon remains for legacy and historical-query workflows. For deeper history beyond RPC's 7-day window, use Hubble/Galexie.
API access for reading chain state. Stellar RPC is the preferred entry point for new projects; Horizon remains for legacy and historical-query workflows. For deeper history beyond RPC's 7-day window, use Hubble/Galexie.
getLatestLedger, getLedgerEntries, getEvents, simulateTransaction, sendTransaction)../dapp/SKILL.md../soroban/SKILL.md../assets/SKILL.md../standards/SKILL.mdStellar provides two API paradigms:
| API | Status | Use Case |
|---|---|---|
| Stellar RPC | Preferred | Soroban, real-time state, new projects |
| Horizon | Legacy-focused | Historical data, legacy applications |
Recommendation: Use Stellar RPC for all new projects. Use Horizon mainly for historical queries and legacy compatibility paths.
Note: SDF directly provides Futurenet public RPC. For Mainnet RPC, select a provider from the RPC providers directory.
| Network | RPC URL |
|---|---|
| Mainnet | Provider-specific endpoint (see RPC providers directory) |
| Testnet | https://soroban-testnet.stellar.org |
| Futurenet | https://rpc-futurenet.stellar.org |
| Local | http://localhost:8000/soroban/rpc |
import * as StellarSdk from "@stellar/stellar-sdk";
const rpc = new StellarSdk.rpc.Server("https://soroban-testnet.stellar.org");
const account = await rpc.getAccount(publicKey);
// Returns account with sequence number for transaction building
const health = await rpc.getHealth();
// { status: "healthy" }
const ledger = await rpc.getLatestLedger();
// { id: "...", sequence: 123456, protocolVersion: 25 }
// Read contract storage
const key = StellarSdk.xdr.LedgerKey.contractData(
new StellarSdk.xdr.LedgerKeyContractData({
contract: new StellarSdk.Address(contractId).toScAddress(),
key: StellarSdk.xdr.ScVal.scvSymbol("Counter"),
durability: StellarSdk.xdr.ContractDataDurability.persistent(),
})
);
const entries = await rpc.getLedgerEntries(key);
if (entries.entries.length > 0) {
const value = StellarSdk.scValToNative(
entries.entries[0].val.contractData().val()
);
}
const simulation = await rpc.simulateTransaction(transaction);
if (StellarSdk.rpc.Api.isSimulationError(simulation)) {
console.error("Simulation failed:", simulation.error);
} else if (StellarSdk.rpc.Api.isSimulationSuccess(simulation)) {
console.log("Cost:", simulation.cost);
console.log("Result:", simulation.result);
}
const response = await rpc.sendTransaction(signedTransaction);
if (response.status === "PENDING") {
// Poll for result
let result = await rpc.getTransaction(response.hash);
while (result.status === "NOT_FOUND") {
await new Promise(r => setTimeout(r, 1000));
result = await rpc.getTransaction(response.hash);
}
if (result.status === "SUCCESS") {
console.log("Success:", result.returnValue);
} else {
console.error("Failed:", result.status);
}
}
const tx = await rpc.getTransaction(txHash);
// status: "SUCCESS" | "FAILED" | "NOT_FOUND"
// returnValue: ScVal (for contract calls)
// ledger: number
const events = await rpc.getEvents({
startLedger: 1000000,
filters: [
{
type: "contract",
contractIds: [contractId],
topics: [
["*", StellarSdk.xdr.ScVal.scvSymbol("transfer").toXDR("base64")],
],
},
],
});
for (const event of events.events) {
console.log("Event:", event.topic, event.value);
}
getTransaction, getEvents, etc. only cover recent datagetLedgers exception: "Infinite Scroll" feature queries any ledger back to genesis via the data lake| Network | Horizon URL |
|---|---|
| Mainnet | https://horizon.stellar.org |
| Testnet | https://horizon-testnet.stellar.org |
| Local | http://localhost:8000 |
import * as StellarSdk from "@stellar/stellar-sdk";
const server = new StellarSdk.Horizon.Server("https://horizon-testnet.stellar.org");
const account = await server.loadAccount(publicKey);
// Full account details including balances, signers, data
const account = await server.loadAccount(publicKey);
for (const balance of account.balances) {
if (balance.asset_type === "native") {
console.log("XLM:", balance.balance);
} else {
console.log(`${balance.asset_code}:`, balance.balance);
}
}
// Account transactions
const transactions = await server
.transactions()
.forAccount(publicKey)
.order("desc")
.limit(10)
.call();
// Specific transaction
const tx = await server
.transactions()
.transaction(txHash)
.call();
const operations = await server
.operations()
.forAccount(publicKey)
.order("desc")
.limit(20)
.call();
for (const op of operations.records) {
console.log(op.type, op.created_at);
}
const payments = await server
.payments()
.forAccount(publicKey)
.order("desc")
.call();
for (const payment of payments.records) {
if (payment.type === "payment") {
console.log(
`${payment.from} -> ${payment.to}: ${payment.amount} ${payment.asset_code || "XLM"}`
);
}
}
const effects = await server
.effects()
.forAccount(publicKey)
.limit(50)
.call();
// Stream transactions
const closeHandler = server
.transactions()
.forAccount(publicKey)
.cursor("now")
.stream({
onmessage: (tx) => {
console.log("New transaction:", tx.hash);
},
onerror: (error) => {
console.error("Stream error:", error);
},
});
// Close stream when done
closeHandler();
try {
const result = await server.submitTransaction(signedTransaction);
console.log("Success:", result.hash);
} catch (error) {
if (error.response?.data?.extras?.result_codes) {
console.error("Error codes:", error.response.data.extras.result_codes);
}
}
// First page
let page = await server.transactions().forAccount(publicKey).limit(10).call();
// Next page
if (page.records.length > 0) {
page = await page.next();
}
// Previous page
page = await page.prev();
// Horizon (old)
const account = await horizonServer.loadAccount(publicKey);
// RPC (new)
const account = await rpc.getAccount(publicKey);
// Note: RPC returns less data, just what's needed for transactions
// Horizon (for classic transactions)
const result = await horizonServer.submitTransaction(tx);
// RPC (for Soroban transactions)
const response = await rpc.sendTransaction(tx);
const result = await pollForResult(response.hash);
// Horizon - full history
const allTxs = await horizonServer
.transactions()
.forAccount(publicKey)
.call();
// RPC - most methods limited to 7 days
// Exception: getLedgers can query back to genesis (Infinite Scroll)
// For full historical data, use:
// 1. Hubble (SDF's BigQuery dataset)
// 2. Galexie (data pipeline)
// 3. Your own indexer
// Horizon - native streaming
server.payments().stream({ onmessage: handlePayment });
// RPC - polling (no native streaming)
async function pollForUpdates() {
const lastLedger = await rpc.getLatestLedger();
// Check for new events/transactions
// Repeat on interval
}
setInterval(pollForUpdates, 5000);
For data older than 7 days (not available via most RPC methods; getLedgers can reach genesis via Infinite Scroll):
-- Query Stellar data in BigQuery
SELECT *
FROM `crypto-stellar.crypto_stellar.history_transactions`
WHERE source_account = 'G...'
ORDER BY created_at DESC
LIMIT 100
Self-hosted data pipeline for processing Stellar ledger data:
RPC "Infinite Scroll" is powered by the Stellar data lake — a cloud-based object store (SEP-0054 format):
s3://aws-public-blockchain/v1.1/stellar/ledgers/pubnet (AWS Open Data)For complex queries, event streaming, or custom data pipelines beyond what RPC/Horizon provide:
See the full indexer directory: https://developers.stellar.org/docs/data/indexers
For a React/Next.js-specific setup, see frontend-stellar-sdk.md. For mainnet RPC, set
STELLAR_MAINNET_RPC_URLfrom a provider in the RPC providers directory.
// lib/stellar-config.ts
import * as StellarSdk from "@stellar/stellar-sdk";
type NetworkConfig = {
rpcUrl: string;
horizonUrl: string;
networkPassphrase: string;
friendbotUrl: string | null;
};
const requireEnv = (name: string): string => {
const value = process.env[name];
if (!value) throw new Error(`Missing required env var: ${name}`);
return value;
};
const configs: Record<string, NetworkConfig> = {
mainnet: {
rpcUrl: requireEnv("STELLAR_MAINNET_RPC_URL"),
horizonUrl: "https://horizon.stellar.org",
networkPassphrase: StellarSdk.Networks.PUBLIC,
friendbotUrl: null,
},
testnet: {
rpcUrl: "https://soroban-testnet.stellar.org",
horizonUrl: "https://horizon-testnet.stellar.org",
networkPassphrase: StellarSdk.Networks.TESTNET,
friendbotUrl: "https://friendbot.stellar.org",
},
local: {
rpcUrl: "http://localhost:8000/soroban/rpc",
horizonUrl: "http://localhost:8000",
networkPassphrase: "Standalone Network ; February 2017",
friendbotUrl: "http://localhost:8000/friendbot",
},
};
const network = process.env.STELLAR_NETWORK || "testnet";
export const config = configs[network];
export const rpc = new StellarSdk.rpc.Server(config.rpcUrl);
export const horizon = new StellarSdk.Horizon.Server(config.horizonUrl);
// RPC errors
try {
const result = await rpc.sendTransaction(tx);
} catch (error) {
if (error.code === 400) {
// Invalid transaction
} else if (error.code === 503) {
// Service unavailable
}
}
// Horizon errors
try {
const result = await horizon.submitTransaction(tx);
} catch (error) {
const extras = error.response?.data?.extras;
if (extras?.result_codes) {
// Detailed error codes
console.log("Transaction:", extras.result_codes.transaction);
console.log("Operations:", extras.result_codes.operations);
}
}
Both RPC and Horizon have rate limits:
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
let lastError: Error;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (error.response?.status === 429) {
// Rate limited - exponential backoff
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
} else {
throw error;
}
}
}
throw lastError;
}
npx claudepluginhub stellar/stellar-dev-skill --plugin stellar-devMaps Stellar Ecosystem Proposals (SEPs) and Core Advancement Proposals (CAPs) to use cases like wallets, anchors, payments, deposits, federation, deep links, and KYC. Also bundles ecosystem references and official docs.
Build Helius-powered Solana applications: transaction sending (Sender), asset/NFT queries (DAS API), WebSocket/gRPC streaming, webhook pipelines, priority fees, wallet analysis, and agent onboarding.
Builds Stellar blockchain apps in Python using stellar-sdk. Covers transaction building/signing, Horizon/Soroban RPC queries, smart contract deployment, XDR/SCVal conversion, async workflows, and SEP integrations.