> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XRP Ledger tooling

> Connect to your Chainstack XRP Ledger node over the rippled JSON-RPC API on HTTPS and the WebSocket API on WSS with curl, wscat, xrpl-py, and xrpl.js, including ledger history limits, transaction submission, and ledger subscriptions.

Get started with a [reliable XRP Ledger RPC endpoint](https://chainstack.com/build-better-with-xrp-ledger/) to use the tools below.

Your Chainstack XRP Ledger node serves the [rippled API](https://xrpl.org/docs/references/http-websocket-apis) two ways: JSON-RPC over the HTTPS endpoint, and the WebSocket API over the WSS endpoint. The official SDKs — [xrpl.js](https://github.com/XRPLF/xrpl.js) and [xrpl-py](https://github.com/XRPLF/xrpl-py) — connect over WSS, and xrpl-py also connects over HTTPS. XRP Ledger has its own method set and does not implement the Ethereum `eth_*` interface, so EVM tooling — ethers.js, web3.py, Hardhat — does not apply here.

## JSON-RPC over HTTPS

Every call is an HTTP POST carrying a `method` and a `params` array. The `params` array holds exactly one object, even when a method takes no arguments — a bare `{}` rather than an empty array.

<CodeGroup>
  ```bash cURL theme={"system"}
  curl YOUR_CHAINSTACK_ENDPOINT \
    -H 'Content-Type: application/json' \
    -d '{"method":"server_info","params":[{}]}'
  ```
</CodeGroup>

The `result` object reports the client version, the ledgers this node holds, and its sync state:

<CodeGroup>
  ```json Response (excerpt) theme={"system"}
  {
    "build_version": "3.3.0",
    "complete_ledgers": "106106987-107266543",
    "server_state": "full"
  }
  ```
</CodeGroup>

Replace `YOUR_CHAINSTACK_ENDPOINT` with your node's HTTPS endpoint. For the credential in that endpoint and the other ways to authenticate, see [Authentication methods for different scenarios](/docs/authentication-methods-for-different-scenarios).

## WebSocket API over WSS

The WSS endpoint serves the rippled WebSocket API, which frames requests differently from JSON-RPC: each message names the method in a `command` field and carries its arguments at the top level, with an optional `id` that the response echoes. A WebSocket connection also supports [subscriptions](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/subscription-methods/subscribe), which push events such as closed ledgers and validated transactions as they happen.

<CodeGroup>
  ```bash wscat theme={"system"}
  wscat -c YOUR_CHAINSTACK_WSS_ENDPOINT
  > {"id": 1, "command": "subscribe", "streams": ["ledger"]}
  ```
</CodeGroup>

The node answers with the subscription result, then sends a `ledgerClosed` message for every new validated ledger:

<CodeGroup>
  ```json Response theme={"system"}
  {"id":1,"result":{"fee_base":10,"ledger_hash":"9FF17722348FDC9F54AC383A8EF40B62BD37B12153D77C611351FDD75C1CCF44","ledger_index":107266586,"ledger_time":843812440,"network_id":0,"reserve_base":1000000,"reserve_inc":200000,"validated_ledgers":"106106987-107266586"},"status":"success","type":"response"}
  {"fee_base":10,"ledger_hash":"582D06B6C94C4F897F1B0F5411DD5FDF523EDA20B4D2895D2920D265FF9F2D9A","ledger_index":107266587,"ledger_time":843812441,"network_id":0,"reserve_base":1000000,"reserve_inc":200000,"txn_count":75,"type":"ledgerClosed","validated_ledgers":"106106987-107266587"}
  ```
</CodeGroup>

Replace `YOUR_CHAINSTACK_WSS_ENDPOINT` with your node's WSS endpoint, which carries the same auth token as the HTTPS endpoint.

## How much ledger history your node holds

XRP Ledger Global Nodes are [Extended](/docs/extended-nodes) — they keep more recent ledgers than a default `rippled` server holds, but not the full chain. The node deletes old ledgers in rotation and holds between 750,000 and 1,500,000 of the most recent ledgers. At the Mainnet close rate of about 3.8 seconds per ledger, that is about 33 to 66 days of history.

Read `complete_ledgers` from `server_info` at runtime and work within it. The lower bound jumps forward each time the node rotates out old ledgers, so treat any specific depth as a moving target rather than a guarantee.

Requesting anything below the window returns `lgrNotFound`:

<CodeGroup>
  ```json Response theme={"system"}
  {
    "result": {
      "error": "lgrNotFound",
      "error_message": "ledgerNotFound",
      "status": "error"
    }
  }
  ```
</CodeGroup>

The same floor applies to transaction history and to account state alike — `account_tx` clamps its search range to the retained window rather than reaching further back. For queries older than the window, use a full-history source such as an [XRP Ledger public full-history server](https://xrpl.org/docs/concepts/networks-and-servers/ledger-history).

## Python

Use the official [xrpl-py](https://github.com/XRPLF/xrpl-py) SDK. Its `JsonRpcClient` talks to your node over HTTPS:

<CodeGroup>
  ```python Python theme={"system"}
  # pip install xrpl-py
  from xrpl.clients import JsonRpcClient
  from xrpl.models.requests import AccountInfo, ServerInfo

  client = JsonRpcClient("YOUR_CHAINSTACK_ENDPOINT")

  info = client.request(ServerInfo()).result["info"]
  print("rippled", info["build_version"], "| ledgers on this node:", info["complete_ledgers"])

  account = client.request(AccountInfo(
      account="rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
      ledger_index="validated",
  )).result["account_data"]
  print("balance (drops):", account["Balance"], "| sequence:", account["Sequence"])
  ```
</CodeGroup>

This prints the node's client version, its retained range, and the queried account's balance in drops:

<CodeGroup>
  ```text Output theme={"system"}
  rippled 3.3.0 | ledgers on this node: 106106987-107266543
  balance (drops): 56775133590 | sequence: 44196
  ```
</CodeGroup>

For subscriptions, use `AsyncWebsocketClient` over the WSS endpoint. This script subscribes to the `ledger` stream and prints each closed ledger:

<CodeGroup>
  ```python Python theme={"system"}
  # pip install xrpl-py
  import asyncio

  from xrpl.asyncio.clients import AsyncWebsocketClient
  from xrpl.models.requests import StreamParameter, Subscribe


  async def main():
      async with AsyncWebsocketClient("YOUR_CHAINSTACK_WSS_ENDPOINT") as client:
          await client.send(Subscribe(streams=[StreamParameter.LEDGER]))
          async for message in client:
              if message.get("type") == "ledgerClosed":
                  print("ledger", message["ledger_index"], "closed with", message["txn_count"], "transactions")


  asyncio.run(main())
  ```
</CodeGroup>

<CodeGroup>
  ```text Output theme={"system"}
  ledger 107266567 closed with 95 transactions
  ledger 107266568 closed with 76 transactions
  ledger 107266569 closed with 110 transactions
  ```
</CodeGroup>

## JavaScript

Use the official [xrpl.js](https://github.com/XRPLF/xrpl.js) SDK. Its `Client` connects to your node over the WSS endpoint:

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  // npm install xrpl
  import { Client } from "xrpl";

  const client = new Client("YOUR_CHAINSTACK_WSS_ENDPOINT");
  await client.connect();

  const { result } = await client.request({ command: "server_info" });
  console.log("rippled", result.info.build_version, "| ledgers:", result.info.complete_ledgers);

  const { result: account } = await client.request({
    command: "account_info",
    account: "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
    ledger_index: "validated",
  });
  console.log("balance (drops):", account.account_data.Balance, "| sequence:", account.account_data.Sequence);

  await client.disconnect();
  ```
</CodeGroup>

<CodeGroup>
  ```text Output theme={"system"}
  rippled 3.3.0 | ledgers: 106106987-107266543
  balance (drops): 56775133590 | sequence: 44196
  ```
</CodeGroup>

### Sign and submit a transaction

`submitAndWait` fills in `Fee`, `Sequence`, and `LastLedgerSequence` from the node, signs the transaction with the wallet locally, submits it, and resolves once a validated ledger contains it:

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  // npm install xrpl
  import { Client, Wallet, xrpToDrops } from "xrpl";

  const client = new Client("YOUR_CHAINSTACK_WSS_ENDPOINT");
  await client.connect();

  const wallet = Wallet.fromSeed("YOUR_SEED");

  const { result } = await client.submitAndWait(
    {
      TransactionType: "Payment",
      Account: wallet.classicAddress,
      Destination: "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
      Amount: xrpToDrops("1"),
    },
    { wallet },
  );
  console.log(result.meta.TransactionResult, "in validated ledger", result.ledger_index);

  await client.disconnect();
  ```
</CodeGroup>

On Testnet, a successful payment prints:

<CodeGroup>
  ```text Output theme={"system"}
  tesSUCCESS in validated ledger 21087026
  ```
</CodeGroup>

### Track new ledgers

Subscribe to the `ledger` stream and handle the `ledgerClosed` event. The node pushes one message for every validated ledger, every few seconds:

<CodeGroup>
  ```javascript JavaScript theme={"system"}
  // npm install xrpl
  import { Client } from "xrpl";

  const client = new Client("YOUR_CHAINSTACK_WSS_ENDPOINT");
  await client.connect();

  client.on("ledgerClosed", (ledger) => {
    console.log(`ledger ${ledger.ledger_index} closed with ${ledger.txn_count} transactions`);
  });

  await client.request({ command: "subscribe", streams: ["ledger"] });
  ```
</CodeGroup>

<CodeGroup>
  ```text Output theme={"system"}
  ledger 107266544 closed with 87 transactions
  ledger 107266545 closed with 86 transactions
  ledger 107266546 closed with 115 transactions
  ```
</CodeGroup>

To follow validated transactions instead, subscribe to the `transactions` stream and handle the `transaction` event.
