Dashboard

Scaling Guide

Stellar API Rate Limits
and Scaling Guide

Understand how Stellar Horizon and Soroban RPC rate limits affect production applications, and learn strategies to scale your access reliably.

Why Rate Limits Matter in Production

Dropped Transactions

When your app hits a 429 response, pending transaction submissions may fail silently. Wallet users see errors, payment confirmations are delayed, and reconciliation gaps appear in your records.

Stale Data

If you cannot poll Horizon frequently enough, your application shows outdated balances, missed incoming payments, and delayed analytics. For trading applications, stale data means missed opportunities.

Service Outages

The public Horizon endpoint has no SLA. During network-wide events or surges in usage, rate limits tighten and availability drops. Applications without a fallback strategy experience downtime.

Public Endpoint Limitations

Horizon (horizon.stellar.org)

  • x No guaranteed uptime or SLA
  • x Rate limits vary and are not documented
  • x No burst capacity for traffic spikes
  • x No caching layer (every request hits the server)
  • x Shared infrastructure with all other users
  • x No support or escalation path

Soroban RPC (soroban-rpc.stellar.org)

  • x Separate rate limits from Horizon
  • x Contract simulation can be expensive
  • x Event streaming may disconnect during load
  • x No analytics or monitoring included
  • x Limited historical data availability
  • x Intended for development, not production

Production Scaling Strategies

Implement these strategies to handle rate limits gracefully and keep your application responsive under load.

Response Caching

Essential

Cache Horizon responses with appropriate TTLs. Network state data can be cached for 5-30 seconds. Historical ledger data can be cached for hours or days since it never changes.

Exponential Backoff

Essential

When you receive a 429 response, wait before retrying. Start with a 1-second delay and double it on each retry, up to a maximum of 30 seconds. Include jitter to avoid thundering herd.

Request Batching

Recommended

Combine multiple account lookups or transaction queries into fewer API calls by using Horizon's pagination and filtering parameters effectively.

Cursor-Based Pagination

Recommended

Use Horizon's cursor parameter to page through large result sets efficiently. Store the last cursor to resume from where you left off without re-fetching data.

SSE Streaming

Recommended

Use Server-Sent Events for real-time data instead of polling. A single SSE connection replaces hundreds of polling requests per minute.

Health Monitoring

Best Practice

Track your API usage, response times, and error rates. Set up alerts when you approach rate limits so you can scale proactively rather than reactively.

Public vs LumenQuery Rate Limits

FeaturePublic HorizonLumenQuery FreeLumenQuery Pro
Monthly RequestsVaries (no guarantee)10,000/month100,000+/month
Burst CapacityNone10 req/sec50 req/sec
Response CachingNoneRedis (30s-10m TTL)Redis (configurable)
Uptime SLANoneBest effort99.9%
Horizon APIYesYesYes
Soroban RPCSeparate endpointUnified accessUnified access
Analytics LayerNoneBasic metricsFull analytics
SSE StreamingYes (may drop)Yes (reliable)Yes (guaranteed)
SupportCommunity onlyEmailPriority support
Rate Limit HeadersInconsistentAlways presentAlways present

Handling Rate Limits in Code

Implement exponential backoff with jitter to handle 429 responses gracefully. This pattern works with any Stellar API provider.

async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  let delay = 1000; // Start with 1 second

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) {
      return response.json();
    }

    if (response.status === 429) {
      // Check for Retry-After header
      const retryAfter = response.headers.get('Retry-After');
      const waitTime = retryAfter
        ? parseInt(retryAfter) * 1000
        : delay + Math.random() * 1000; // Add jitter

      console.warn(
        `Rate limited (attempt ${attempt + 1}/${maxRetries + 1}). ` +
        `Waiting ${Math.round(waitTime / 1000)}s...`
      );

      if (attempt < maxRetries) {
        await new Promise((r) => setTimeout(r, waitTime));
        delay *= 2; // Exponential backoff
        continue;
      }
    }

    throw new Error(`API request failed: ${response.status}`);
  }
}

// Usage with LumenQuery API
const ledger = await fetchWithRetry(
  'https://lumenquery.io/api/analytics/network?range=24h'
);

// Usage with public Horizon (more likely to hit limits)
const account = await fetchWithRetry(
  'https://horizon.stellar.org/accounts/GABC...',
  { headers: { 'Accept': 'application/json' } }
);

Learn More

Frequently Asked Questions

What are the rate limits on the public Stellar Horizon API?
The SDF-operated public Horizon instance at horizon.stellar.org enforces rate limits that vary but are generally around 1 request per second for unauthenticated users. During peak network activity, limits may be tightened further. There is no SLA or guarantee of availability.
What happens when I exceed Stellar API rate limits?
When you exceed rate limits, the Horizon API returns HTTP 429 (Too Many Requests) responses. Your application must handle this gracefully with retry logic and exponential backoff, or risk dropped data, broken user experiences, and incomplete transaction processing.
How do I scale beyond public Stellar API rate limits?
You have three main options: self-host a Horizon instance (complex and expensive), use a managed provider like LumenQuery (simplest), or implement aggressive caching and request batching. Most production applications combine a managed API provider with application-level caching.
Does self-hosting Horizon remove rate limits?
Self-hosting removes external rate limits, but you are now responsible for server provisioning, database management (PostgreSQL), captive core synchronization, monitoring, security patching, and disaster recovery. The infrastructure cost for a reliable Horizon instance starts at $200-500/month.
What rate limits does LumenQuery offer?
LumenQuery offers tiered rate limits starting with 10,000 requests/month on the free plan. Paid plans increase limits to 100,000+ requests/month with burst capacity for traffic spikes. All plans include built-in caching that reduces the effective number of upstream requests.
How does caching help with Stellar API rate limits?
LumenQuery uses Redis-backed caching with configurable TTLs. Network metrics are cached for 30 seconds, historical data for 5-10 minutes. This means repeated requests for the same data are served from cache without consuming your rate limit quota, and response times drop from 200-500ms to under 10ms.
Are Soroban RPC rate limits different from Horizon?
Yes. The public Soroban RPC endpoint has its own rate limits, separate from Horizon. Soroban RPC handles smart contract simulation, state queries, and event streaming. LumenQuery proxies both Horizon and Soroban RPC, applying unified rate limits and caching across both APIs.

Scale Past Rate Limits

Get reliable Stellar API access with guaranteed rate limits, built-in caching, and unified Horizon + Soroban RPC endpoints. Free tier available.