Skip to content
Alchemy Logo

Stellar WebSocket subscriptions

Connect to Stellar mainnet or testnet and receive live JSON-RPC notifications.

Receive new Stellar activity over a WebSocket connection. Use stellar_subscribe to start a subscription and stellar_unsubscribe to stop it.

Create an API key in the Alchemy Dashboard and replace YOUR_API_KEY in the endpoint:

NetworkEndpoint
Mainnetwss://stellar-mainnet.g.alchemy.com/v2/YOUR_API_KEY
Testnetwss://stellar-testnet.g.alchemy.com/v2/YOUR_API_KEY

This Node.js 22+ example subscribes to closed ledgers. Set ALCHEMY_API_KEY in your environment first.

const apiKey = process.env.ALCHEMY_API_KEY;
if (!apiKey) throw new Error('Set ALCHEMY_API_KEY');
 
const ws = new WebSocket(
  `wss://stellar-mainnet.g.alchemy.com/v2/${encodeURIComponent(apiKey)}`,
);
ws.addEventListener('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'stellar_subscribe',
    params: ['newLedgers'],
  }));
});
ws.addEventListener('message', ({ data }) => console.log(JSON.parse(data)));
ws.addEventListener('error', () => console.error('WebSocket connection failed'));
ws.addEventListener('close', ({ code, reason }) => console.log(code, reason));

These methods are WebSocket-only. Send positional params arrays, not the named parameter objects used by Stellar's HTTP RPC methods.

Match the response id to your request and keep the returned subscription ID:

{"jsonrpc":"2.0","id":1,"result":"0x0123456789abcdef0123456789abcdef"}

Later notifications use method: "stellar_subscription". Their params.subscription identifies your subscription and params.result contains one record. Check for an error object before treating a response as a successful subscription.

TopicRecordsFilters
newLedgersClosed ledgers with header and metadata XDRNone
eventsContract and system events, including Soroban token eventstype, contractIds, topics
transactionsIncluded transactions with XDR-JSON envelopes and resultsstatus, accounts
paymentsSuccessful classic payment and path-payment operationsaccounts, from, to

Read the complete subscription reference for request and response shapes, examples for every topic, and filter rules. You can also download the customer guide and message JSON Schema.

Omit the filter or pass {} to receive all eligible records. Filter fields are ANDed together; entries in address arrays are ORed. Address arrays accept 1–100 valid StrKeys. G and M account addresses match exactly; an M address does not implicitly match its underlying G address. Use C addresses only in contractIds.

For Soroban transfers, use events, not payments. Topic filters contain base64 XDR segments or "*". Include both three-segment and four-segment patterns if you want both common transfer event formats:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "stellar_subscribe",
  "params": ["events", {
    "type": "contract",
    "topics": [
      ["AAAADwAAAAh0cmFuc2Zlcg==", "*", "*"],
      ["AAAADwAAAAh0cmFuc2Zlcg==", "*", "*", "*"]
    ]
  }]
}

The encoded first segment is the symbol transfer. Check inSuccessfulContractCall and the transaction result before interpreting an event as a completed transfer. Custom contracts can use different formats.

Send the subscription ID on the same connection:

{"jsonrpc":"2.0","id":3,"method":"stellar_unsubscribe","params":["0x0123456789abcdef0123456789abcdef"]}

A result of true means it was removed; false means it was not found on that connection. Other subscriptions remain active. Notifications already in flight can arrive while you unsubscribe. See the unsubscribe reference.

  • Subscriptions are live-only. There is no historical start ledger, replay, resume token, or pending-transaction feed. Acknowledgement confirms acceptance, not immediate delivery or delivery from the instant of your request.
  • Delivery is best effort. Reconnects require new subscriptions and new IDs; there is no durable exactly-once or at-least-once guarantee. There is no fixed notification latency guarantee.
  • If you need complete records, persist progress, reconnect with backoff and jitter, buffer live arrivals, backfill an overlapping range through HTTP RPC, and deduplicate. Historical RPC is limited by retained history.
  • transactions.accounts matches explicit transaction participants, not every account whose balance or contract state changes.
  • payments excludes failed transactions, account creation/merge, and Soroban transfers. Amounts remain integer-unit strings. Path-payment bounds are not executed amounts.
  • Payloads can be large. Process notifications promptly, configure incoming message limits, and bound client queues. Your plan's connection, subscription, and usage limits still apply.
Was this page helpful?