Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
stellar avatar

Data

  • 257 installs
  • 50 repo stars
  • Updated August 4, 2026
  • stellar/stellar-dev-skill

The Stellar data skill is a stellar-dev-skill reference so developers can query chain state via Stellar RPC and Horizon for balances, transactions, operations, and contract events.

About

The stellar-dev-skill data module teaches agents how to read Stellar chain data through RPC and Horizon with migration guidance and historical options. It includes TypeScript patterns for accounts, transactions, operations, contract events, and streaming, plus when to use Hubble or Galexie beyond RPC recent window. Reach for it whenever you implement indexers, dashboards, or debugging flows that need authoritative ledger queries.

  • Stellar RPC preferred; Horizon legacy for historical queries
  • Covers getLedgerEntries, getEvents, simulateTransaction, and sendTransaction polling
  • Seven-day RPC history limits with Hubble/Galexie for deep history
  • TypeScript examples with @stellar/stellar-sdk rpc.Server and Horizon.Server
  • Cross-links to dapp, smart-contracts, assets, and standards skills

Data by the numbers

  • 257 all-time installs (skills.sh)
  • +37 installs in the week ending Jul 27, 2026 (Skillselion tracking)
  • Ranked #75 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/stellar/stellar-dev-skill --skill data

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs257
repo stars50
Last updatedAugust 4, 2026
Repositorystellar/stellar-dev-skill

How do you choose RPC versus Horizon, handle pagination and streaming, and reach genesis-era history when building Stellar data workflows?

Query Stellar balances, transactions, contract events, and historical ledgers via RPC and Horizon when building indexers or analytics.

Who is it for?

Developers building Stellar indexers, analytics, or dapp read paths who use @stellar/stellar-sdk and need method-level examples.

Skip if: Teams only submitting transactions without reading ledger data—use the dapp skill instead.

When should I use this skill?

You need getLatestLedger, getEvents, Horizon pagination, or migration notes while implementing a Stellar data task.

What you get

Working query patterns, endpoint choices, and code snippets for RPC/Horizon reads plus pointers to deep-history tools.

Files

SKILL.mdMarkdownGitHub ↗

Stellar Data: RPC + Horizon

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.

When to use this skill

  • Calling Stellar RPC methods (getLatestLedger, getLedgerEntries, getEvents, simulateTransaction, sendTransaction)
  • Querying Horizon endpoints (accounts, transactions, operations, effects, ledgers)
  • Streaming live events or operations
  • Pulling historical data beyond RPC's 7-day window (Hubble, Galexie)
  • Choosing between RPC and Horizon for a given workflow

Related skills

  • Building transactions to send → ../dapp/SKILL.md
  • Soroban contract simulation and event emission → ../soroban/SKILL.md
  • Asset balance and trustline lookups → ../assets/SKILL.md
  • Standards (SEP-7 deeplinks, SEP-10 auth) → ../standards/SKILL.md

---

Overview

Stellar provides two API paradigms:

APIStatusUse Case
Stellar RPCPreferredSoroban, real-time state, new projects
HorizonLegacy-focusedHistorical data, legacy applications

Recommendation: Use Stellar RPC for all new projects. Use Horizon mainly for historical queries and legacy compatibility paths.

Quick Navigation

Stellar RPC

Endpoints

Note: SDF directly provides Futurenet public RPC. For Mainnet RPC, select a provider from the RPC providers directory.
NetworkRPC URL
MainnetProvider-specific endpoint (see RPC providers directory)
Testnethttps://soroban-testnet.stellar.org
Futurenethttps://rpc-futurenet.stellar.org
Localhttp://localhost:8000/soroban/rpc

Setup

import * as StellarSdk from "@stellar/stellar-sdk";

const rpc = new StellarSdk.rpc.Server("https://soroban-testnet.stellar.org");

Key Methods

Get Account
const account = await rpc.getAccount(publicKey);
// Returns account with sequence number for transaction building
Get Health
const health = await rpc.getHealth();
// { status: "healthy" }
Get Latest Ledger
const ledger = await rpc.getLatestLedger();
// { id: "...", sequence: 123456, protocolVersion: 25 }
Get Ledger Entries
// 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()
  );
}
Simulate Transaction
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);
}
Send Transaction
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);
  }
}
Get Transaction
const tx = await rpc.getTransaction(txHash);
// status: "SUCCESS" | "FAILED" | "NOT_FOUND"
// returnValue: ScVal (for contract calls)
// ledger: number
Get Events
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);
}

RPC Limitations

  • 7-day history for most methods: getTransaction, getEvents, etc. only cover recent data
  • `getLedgers` exception: "Infinite Scroll" feature queries any ledger back to genesis via the data lake
  • No streaming: Poll for updates (no WebSocket)
  • Contract-focused: Limited classic Stellar data

Horizon API (Legacy)

Endpoints

NetworkHorizon URL
Mainnethttps://horizon.stellar.org
Testnethttps://horizon-testnet.stellar.org
Localhttp://localhost:8000

Setup

import * as StellarSdk from "@stellar/stellar-sdk";

const server = new StellarSdk.Horizon.Server("https://horizon-testnet.stellar.org");

Common Operations

Load Account
const account = await server.loadAccount(publicKey);
// Full account details including balances, signers, data
Get Account Balances
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);
  }
}
Get Transactions
// Account transactions
const transactions = await server
  .transactions()
  .forAccount(publicKey)
  .order("desc")
  .limit(10)
  .call();

// Specific transaction
const tx = await server
  .transactions()
  .transaction(txHash)
  .call();
Get Operations
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);
}
Get Payments
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"}`
    );
  }
}
Get Effects
const effects = await server
  .effects()
  .forAccount(publicKey)
  .limit(50)
  .call();
Streaming (Server-Sent Events)
// 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();
Submit Transaction
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);
  }
}

Pagination

// 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();

Migration: Horizon to RPC

Account Loading

// 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

Transaction Submission

// 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);

Historical Data

// 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

Streaming Replacement

// 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);

Historical Data Access

For data older than 7 days (not available via most RPC methods; getLedgers can reach genesis via Infinite Scroll):

Hubble (BigQuery)

-- Query Stellar data in BigQuery
SELECT *
FROM `crypto-stellar.crypto_stellar.history_transactions`
WHERE source_account = 'G...'
ORDER BY created_at DESC
LIMIT 100

Galexie

Self-hosted data pipeline for processing Stellar ledger data:

  • https://github.com/stellar/galexie

Data Lake

RPC "Infinite Scroll" is powered by the Stellar data lake — a cloud-based object store (SEP-0054 format):

  • Public access: s3://aws-public-blockchain/v1.1/stellar/ledgers/pubnet (AWS Open Data)
  • Self-host: Use Galexie to export to AWS S3 or Google Cloud Storage
  • Hosted: Quasar (Lightsail Network) provides hosted Galexie Data Lake + Archive RPC endpoints
  • Size: ~3.8TB, growing ~0.5TB/year
  • Cost: ~$160/month self-hosted ($60 compute + $100 storage)
  • Docs: https://developers.stellar.org/docs/data/apis/rpc/admin-guide/data-lake-integration

Third-Party Indexers

For complex queries, event streaming, or custom data pipelines beyond what RPC/Horizon provide:

  • Mercury — Stellar-native indexer with Retroshades, GraphQL API (https://mercurydata.app)
  • SubQuery — Multi-chain indexer with Stellar/Soroban support, event handlers (https://subquery.network)
  • Goldsky — Real-time data replication pipelines and subgraphs (https://goldsky.com)
  • StellarExpert API — Free, no-auth REST API for assets, accounts, ledger resolution (https://stellar.expert/openapi.html)

See the full indexer directory: https://developers.stellar.org/docs/data/indexers

Network Configuration

For a React/Next.js-specific setup, see frontend-stellar-sdk.md.
For mainnet RPC, set STELLAR_MAINNET_RPC_URL from a provider in the RPC providers directory.

Environment-Based Setup

// 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);

Best Practices

Use RPC for:

  • New application development
  • Soroban contract interactions
  • Transaction simulation and submission
  • Real-time account state

Use Horizon for:

  • Historical transaction queries
  • Payment streaming
  • Legacy application maintenance
  • Rich account metadata

Error Handling

// 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);
  }
}

Rate Limiting

Both RPC and Horizon have rate limits:

  • Use exponential backoff for retries
  • Cache responses where appropriate
  • Consider running your own nodes for high-volume applications
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;
}

Related skills

FAQ

Which API should new projects use?

SKILL.md recommends Stellar RPC for new work and Horizon mainly for historical or legacy compatibility paths.

What is RPC history limitation?

Most RPC methods cover about seven days; getLedgers infinite scroll and Hubble/Galexie handle deeper history per the doc.

Does RPC support WebSocket streaming?

No—RPC has no streaming; the skill notes polling and Horizon streaming for live updates.

Web3 & Blockchainpipelinesanalytics

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.