Which endpoint to use?
If you're building on the XRP Ledger, knowing when to use WebSocket subscriptions vs REST HTTP-RPC calls can be the difference between a snappy app and one that constantly lags behind the chain.
Honeycluster TeamHoneycluster Team-
Education
Which endpoint to use?

The XRP Ledger exposes its API through two transport protocols: HTTP JSON-RPC and WebSocket. Both give you access to the same set of commands, but the way they handle connections, latency, and data flow is fundamentally different. Picking the wrong one for your use case means either wasted bandwidth or missed ledger events.

This guide breaks down when to use each, with real code examples you can run against Honeycluster endpoints today.

HTTP JSON-RPC
##

HTTP JSON-RPC is the simpler of the two. You send a POST request with a JSON body, the server responds with JSON, and the connection closes. Stateless, familiar, and easy to debug with curl.

When to use HTTP
###
  • One-off queries -- account balances, transaction lookups, server state checks
  • Backend services that need data on demand rather than continuously
  • Serverless functions (Lambda, Cloudflare Workers) where persistent connections are impractical
  • Simple scripts and CLI tools
Example: fetch account info via HTTP
###
JavaScript
const response = await fetch("https://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-rpc/", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    method: "account_info",
    params: [
      {
        account: "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
        ledger_index: "validated"
      }
    ]
  })
});

const data = await response.json();
console.log("Balance:", data.result.account_data.Balance);

The request/response cycle is straightforward. No handshake overhead beyond the standard TCP + TLS setup, and HTTP/2 connection reuse keeps subsequent calls fast.

Example: look up a transaction
###
JavaScript
const response = await fetch("https://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-rpc/", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    method: "tx",
    params: [
      {
        transaction: "E2F28FBE4A206D... (tx hash)",
        binary: false
      }
    ]
  })
});

const tx = await response.json();
console.log("Transaction type:", tx.result.TransactionType);
console.log("Validated:", tx.result.validated);
WebSocket
##

WebSocket opens a persistent, full-duplex connection. Once the handshake completes, both client and server can push messages at any time without the overhead of new HTTP requests. This is what you want when the ledger needs to talk to you, not the other way around.

When to use WebSocket
###
  • Subscriptions -- listen for new ledger closes, transaction streams, order book changes
  • Real-time dashboards that display live chain state
  • Payment monitoring where you need instant notification of incoming transactions
  • High-frequency request patterns where the per-request overhead of HTTP adds up
Example: subscribe to ledger closings
###
JavaScript
const WebSocket = require("ws");

const ws = new WebSocket("wss://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-ws/");

ws.on("open", () => {
  ws.send(
    JSON.stringify({
      command: "subscribe",
      streams: ["ledger"]
    })
  );
  console.log("Subscribed to ledger stream");
});

ws.on("message", (data) => {
  const msg = JSON.parse(data);

  if (msg.type === "ledgerClosed") {
    console.log(`Ledger #${msg.ledger_index} closed`);
    console.log(`  Transactions: ${msg.txn_count}`);
    console.log(`  Close time:   ${msg.ledger_time}`);
  }
});

ws.on("close", () => {
  console.log("Connection closed -- implement reconnection logic here");
});
Example: monitor an account for payments
###
JavaScript
const WebSocket = require("ws");

const ws = new WebSocket("wss://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-ws/");
const WATCHED_ACCOUNT = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";

ws.on("open", () => {
  ws.send(
    JSON.stringify({
      command: "subscribe",
      accounts: [WATCHED_ACCOUNT]
    })
  );
});

ws.on("message", (data) => {
  const msg = JSON.parse(data);

  if (msg.transaction && msg.transaction.TransactionType === "Payment") {
    console.log("Payment detected!");
    console.log(`  From: ${msg.transaction.Account}`);
    console.log(`  To:   ${msg.transaction.Destination}`);
    console.log(`  Amount: ${JSON.stringify(msg.transaction.Amount)}`);
  }
});
Comparison
##
HTTP JSON-RPCWebSocket
Connection model
Stateless, one request per connection (or reused via HTTP/2)
Persistent, full-duplex
Latency
Higher per-call due to connection setup
Lower after initial handshake
Subscriptions
Not supported
Native support via subscribe command
Overhead
HTTP headers on every request
Minimal frame overhead after handshake
Reconnection
Not needed (stateless)
Must be handled by the client
Best for
On-demand queries, serverless, scripts
Streaming, real-time monitoring, high-throughput
Ease of use
Very simple (fetch / curl)
Requires connection lifecycle management
Firewall friendliness
Works everywhere
Occasionally blocked by corporate proxies
Common mistakes
##
1. Polling HTTP when you should subscribe
###

This is the most frequent anti-pattern. Developers write a setInterval that hits the HTTP endpoint every second to check for new ledgers or transactions.

JavaScript
// Don't do this
setInterval(async () => {
  const res = await fetch("https://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-rpc/", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ method: "ledger", params: [{ ledger_index: "validated" }] })
  });
  const data = await res.json();
  // check if ledger index changed...
}, 1000);

This wastes bandwidth, adds latency (you only discover new ledgers at the next poll interval), and puts unnecessary load on the server. Use a WebSocket subscription instead. You get the data pushed to you the moment the ledger closes.

Rule of thumb

If you find yourself polling an HTTP endpoint more than once every 30 seconds for the same type of data, you almost certainly want a WebSocket subscription.

2. Not handling WebSocket reconnection
###

WebSocket connections drop. Servers restart, networks hiccup, load balancers rotate. If your code assumes the connection will stay open forever, you will miss events silently.

Always implement reconnection with exponential backoff:

JavaScript
function connect() {
  const ws = new WebSocket("wss://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-ws/");

  ws.on("open", () => {
    retryDelay = 1000; // reset on successful connect
    ws.send(JSON.stringify({ command: "subscribe", streams: ["ledger"] }));
  });

  ws.on("message", (data) => {
    // handle messages
  });

  ws.on("close", () => {
    console.log(`Reconnecting in ${retryDelay}ms...`);
    setTimeout(connect, retryDelay);
    retryDelay = Math.min(retryDelay * 2, 30000);
  });
}

let retryDelay = 1000;
connect();

Don't forget resubscription

After reconnecting, your previous subscriptions are gone. You must re-send your subscribe commands inside the open handler every time.

3. Ignoring the id field
###

Both protocols support an id field in requests so you can match responses to their originating calls. This is especially important on WebSocket where multiple responses can arrive interleaved. Always set a unique id on each request and correlate it on the response side.

Json
{
  "id": "account-check-42",
  "command": "account_info",
  "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
  "ledger_index": "validated"
}
Honeycluster endpoints
##

Honeycluster provides both HTTP and WebSocket endpoints for the XRP Ledger, optimized for low latency and high availability.

ProtocolEndpoint
HTTP JSON-RPC
https://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-rpc/
WebSocket
wss://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-ws/

Both endpoints support the full XRPL API command set. Requests are routed to geographically distributed nodes, and connections are load-balanced automatically.

Rate limits

Free-tier access is available for development and testing. For production workloads that require higher throughput or guaranteed SLAs, check out our infrastructure plans on the Honeycluster dashboard.

Choosing the right tool
##

The decision usually comes down to a single question: does your application need to react to chain events as they happen?

  • If yes -- use WebSocket. Subscribe to the streams you care about and let the server push data to you.
  • If no -- use HTTP. Make a request when you need data, get the response, move on.

Many production applications use both. A common pattern is to maintain a WebSocket connection for real-time ledger and transaction monitoring, while using HTTP for ad-hoc lookups triggered by user actions (searching for a transaction hash, checking a balance on demand).

Get started
##

Spin up a quick test right now. Open a terminal and hit the HTTP endpoint:

Bash
curl -s -X POST https://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-rpc/ \
  -H "Content-Type: application/json" \
  -d '{"method":"server_info","params":[{}]}' | jq .result.info.validated_ledger

Or open a WebSocket connection:

Bash
wscat -c wss://743ad329-0d975b0d.sandblocks.dev/proxy/xrpl-ws/ \
  -x '{"command":"subscribe","streams":["ledger"]}'

Both should return data within milliseconds. From there, integrate the right protocol into your stack and start building.

Head over to the Honeycluster Dashboard to grab your API keys and explore the full endpoint documentation. If you have questions, drop into our community channels -- we are always happy to help developers ship faster on the XRP Ledger.

Build on infrastructure you can trust

Managed nodes, real-time indexing, and production-grade APIs for the XRP Ledger.

Get started