# WebSocket subscriptions

Source: https://docs.graphops.xyz/rpc/guides/websocket-subscriptions

Update balances, send notifications, or start jobs as new blocks and matching events arrive.
This guide subscribes to USDC `Transfer` logs over WebSocket, then shows how to fill the gap with
`eth_getLogs` when the connection drops, because a new subscription only delivers new events.

## Prerequisites

* An API key that includes RPC.
* WebSocket access for the target chain.
* A WebSocket client. Use route-token authentication when the client cannot send custom headers.
* Durable progress tracking for the last processed block and log identity.

## Subscribe to logs

This request subscribes to USDC `Transfer` logs over the Ethereum mainnet WebSocket endpoint. The
endpoint uses route-token authentication, so the URL contains your API key; redact it from logs,
metrics labels, and support output.

Prerequisites

1. Install Node.js.

2. Install tsx and ws. `npm install tsx ws`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

Tested with Node.js 24.22.1, tsx 4.23.15, ws 8.22.0.

[Example project](/examples/rpc.guides.websocket-subscriptions.ts-1.tar.gz)

```typescript
import WebSocket from "ws";

const socket = new WebSocket(
  `wss://rpc.graphops.xyz/v1/evm/1/${process.env.GRAPHOPS_API_KEY}`,
);
socket.once("error", (error) => { throw error; });

socket.once("open", () => {
  socket.send(
    JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "eth_subscribe",
      params: [
        "logs",
        {
          address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
          // keccak256("Transfer(address,address,uint256)"), the Transfer event topic.
          topics: [
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
          ],
        },
      ],
    }),
  );
});

let done = false; // This demonstration prints one notification.
socket.on("message", (data) => {
  const message = JSON.parse(data.toString());
  if (message.error) throw new Error(JSON.stringify(message.error));
  // The first reply carries the subscription id; each log then arrives as an
  // eth_subscription notification.
  if (message.method !== "eth_subscription" || done) return;
  done = true;
  console.log(JSON.stringify(message));
  socket.close();
});

```

Output

```json
{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "result": {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x00000000000000000000000093228d328c9c74c2bfe9f97638bbb5ef322f2bd5",
        "0x00000000000000000000000021a1adfc2b88b1479f1307817e900addbc15b3f2"
      ],
      "data": "0x000000000000000000000000000000000000000000000000000000002f237ebc",
      "blockHash": "0x083457ed25b83ce5f2ee9fa527e4f08a9ea7b98cceb6b7cccb23383d5b2f5abe",
      "blockNumber": "0x1911630",
      "blockTimestamp": "0x6ae0e297",
      "transactionHash": "0x104106af1f15a9bfaf0e0840626b316dcbfc6f89f557942170d031943d8c184c",
      "transactionIndex": "0x8",
      "logIndex": "0x4",
      "removed": false
    },
    "subscription": "0xfbcbd5f54eff400f111f11b1c34cedee"
  }
}
```

Transfer amount: 790,855,356 base units, 790.855356 USDC

Block in decimal: 26,285,616

Subscription ID returned by eth\_subscribe

The program prints one notification, then closes the subscription. The subscription ID in
`params.subscription` identifies the subscription; notifications carry no request `id`.

## Use a client library

Client libraries manage the subscription for you over the route-token WebSocket endpoint: viem with
`watchEvent`, go-ethereum with `SubscribeFilterLogs`, alloy with `subscribe_logs`, and web3.py with
its asynchronous WebSocket provider.

TypeScript · viem

Prerequisites

1. Install Node.js.

2. Install tsx and viem. `npm install tsx viem`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

Tested with Node.js 24.22.1, tsx 4.23.15, viem 2.57.10.

[Example project](/examples/rpc.guides.websocket-subscriptions.ts-4.tar.gz)

```typescript
import { createPublicClient, parseAbiItem, webSocket } from "viem";
import { mainnet } from "viem/chains";

const client = createPublicClient({
  chain: mainnet,
  transport: webSocket(`wss://rpc.graphops.xyz/v1/evm/1/${process.env.GRAPHOPS_API_KEY}`),
});

let done = false; // This demonstration stops after the first log.
const unwatch = client.watchEvent({
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  event: parseAbiItem(
    "event Transfer(address indexed from, address indexed to, uint256 value)",
  ),
  // Over WebSocket, viem delivers each eth_subscription log as a one-item array.
  onLogs: async (logs) => {
    if (done) return;
    done = true;
    console.log(
      JSON.stringify(logs, (_, value) =>
        typeof value === "bigint" ? value.toString() : value,
      ),
    );
    unwatch();
    // Close the socket so the process can exit.
    const socket = await client.transport.getRpcClient();
    socket.close();
  },
  onError: (error) => { throw error; },
});

```

Output

```json
[
  {
    "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
      "0x00000000000000000000000023617e59a5925b2a4bf75d73ff6711cd0b29de85"
    ],
    "data": "0x0000000000000000000000000000000000000000000000000000003114368392",
    "blockHash": "0x37db6e4e06418099e0dde9c71a1330ceb05843f1d79ef4440a27498822c6a03e",
    "blockNumber": "26285617",
    "blockTimestamp": "1793122979",
    "transactionHash": "0x205c7d8e77b18b559b10351720edf1136bb23932cfc27f646d3848730d3de77a",
    "transactionIndex": 0,
    "logIndex": 10,
    "removed": false,
    "args": {
      "from": "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640",
      "to": "0x23617e59A5925b2A4Bf75d73ff6711cD0b29De85",
      "value": "210792514450"
    },
    "eventName": "Transfer"
  }
]
```

Store as your last processed block

true when a reorg reverses this log

Go · ethclient

Prerequisites

1. Install Go.

2. Install github.com/ethereum/go-ethereum. `go get github.com/ethereum/go-ethereum`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

Tested with Go 1.26.0, github.com/ethereum/go-ethereum v1.17.7.

[Example project](/examples/rpc.guides.websocket-subscriptions.go-7.tar.gz)

```go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"

	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	ctx := context.Background()
	client, err := ethclient.DialContext(ctx,
		fmt.Sprintf("wss://rpc.graphops.xyz/v1/evm/1/%s", os.Getenv("GRAPHOPS_API_KEY")))
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	logs := make(chan types.Log)
	sub, err := client.SubscribeFilterLogs(ctx, ethereum.FilterQuery{
		Addresses: []common.Address{common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")},
		// keccak256("Transfer(address,address,uint256)"), the Transfer event topic.
		Topics: [][]common.Hash{{
			common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
		}},
	}, logs)
	if err != nil {
		log.Fatal(err)
	}
	defer sub.Unsubscribe()

	// This demonstration stops after the first log.
	select {
	case err := <-sub.Err():
		log.Fatal(err)
	case transfer := <-logs:
		payload, err := json.Marshal(transfer)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(string(payload))
	}
}

```

Output

```json
{
  "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
  "topics": [
    "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
    "0x000000000000000000000000000000000004444c5dc75cb358380d2e3de08a90",
    "0x0000000000000000000000000000000aa232009084bd71a5797d089aa4edfad4"
  ],
  "data": "0x0000000000000000000000000000000000000000000000000000000000000055",
  "blockNumber": "0x1911634",
  "transactionHash": "0x078a0450b9831ce36fe6b7aed8b4cd34a5e8a5da626d1fbf8be2efa3863e867f",
  "transactionIndex": "0x0",
  "blockHash": "0x7931a9fc337c615e67690a3083685a5680a72653718c13451f7697ea856b14f3",
  "blockTimestamp": "0x6ae0e2c7",
  "logIndex": "0x0",
  "removed": false
}
```

Store as your last processed block

true when a reorg reverses this log

Rust · alloy

Prerequisites

1. Install Rust.

2. Install alloy, reqwest, tokio, and serde\_json. `cargo add alloy reqwest tokio serde_json -F alloy/provider-ws -F alloy/sol-types -F alloy/contract -F reqwest/json -F tokio/macros -F tokio/rt-multi-thread`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

Tested with Rust 1.98.1, alloy 2.5.0, reqwest 0.13.5, tokio 1.48.0, serde\_json 1.0.145.

[Example project](/examples/rpc.guides.websocket-subscriptions.rust-8.tar.gz)

```rust
use alloy::primitives::address;
use alloy::providers::{Provider, ProviderBuilder, WsConnect};
use alloy::rpc::types::Filter;
use std::{env, error::Error};
use tokio::sync::broadcast::error::RecvError;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let ws = WsConnect::new(format!(
        "wss://rpc.graphops.xyz/v1/evm/1/{}",
        env::var("GRAPHOPS_API_KEY")?
    ));
    let provider = ProviderBuilder::new().connect_ws(ws).await?;

    let filter = Filter::new()
        .address(address!("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"))
        .event("Transfer(address,address,uint256)");
    // A block's matching logs arrive together. alloy buffers 16 by default, so make room for a
    // busy block.
    let mut subscription = provider.subscribe_logs(&filter).channel_size(1024).await?;

    // This demonstration stops after the first log.
    let log = loop {
        match subscription.recv().await {
            Ok(log) => break log,
            // A full buffer drops its oldest logs. Backfill them with eth_getLogs.
            Err(RecvError::Lagged(skipped)) => eprintln!("Skipped {skipped} logs"),
            Err(error) => return Err(error.into()),
        }
    };
    println!("{}", serde_json::to_string(&log)?);
    Ok(())
}

```

Output

```json
{
  "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
  "topics": [
    "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
    "0x00000000000000000000000051c72848c68a965f66fa7a88855f9f7784502a7f",
    "0x00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640"
  ],
  "data": "0x00000000000000000000000000000000000000000000000000000013247b1da8",
  "blockHash": "0x09fffa722f278b60998290f6534850d5b2248e083ada05d332aa684f24f8302e",
  "blockNumber": "0x1911633",
  "blockTimestamp": "0x6ae0e2bb",
  "transactionHash": "0xcd465a3b90aa352f8e1d7e989d9cc2171987ed5ee7a9e10b8cf922948ec3d9a4",
  "transactionIndex": "0x0",
  "logIndex": "0x1",
  "removed": false
}
```

Store as your last processed block

true when a reorg reverses this log

Python · web3.py

Prerequisites

1. Install Python.

2. Install web3. `python -m pip install web3`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

Tested with Python 3.12.12, web3 8.0.0.

[Example project](/examples/rpc.guides.websocket-subscriptions.python-6.tar.gz)

```python
import asyncio
import os

from web3 import AsyncWeb3, Web3, WebSocketProvider

async def main():
    async with AsyncWeb3(
        WebSocketProvider(f"wss://rpc.graphops.xyz/v1/evm/1/{os.environ['GRAPHOPS_API_KEY']}")
    ) as w3:
        await w3.eth.subscribe(
            "logs",
            {
                "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
                # keccak256("Transfer(address,address,uint256)"), the Transfer event topic.
                "topics": [
                    "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
                ],
            },
        )
        # This demonstration prints the first notification, then disconnects.
        async for payload in w3.socket.process_subscriptions():
            # to_json serializes web3's HexBytes and AttributeDict values.
            print(Web3.to_json(payload))
            break

asyncio.run(main())

```

Output

```json
{
  "subscription": "0xaaa21ba7cf4afa47a687264a16194fa6",
  "result": {
    "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
      "0x00000000000000000000000023617e59a5925b2a4bf75d73ff6711cd0b29de85"
    ],
    "data": "0x0000000000000000000000000000000000000000000000000000002ba4a13967",
    "blockHash": "0xba80b9e7126dc40fe13ab8eaa2d6830a4982c0d514433696c990b86a281b4313",
    "blockNumber": 26285618,
    "blockTimestamp": "0x6ae0e2af",
    "transactionHash": "0xcf0201a45453ea0cbb49b656fcfacc0ca856e3e6f440e24e01642735b56982b2",
    "transactionIndex": 0,
    "logIndex": 10,
    "removed": false
  }
}
```

The id eth\_subscribe returned

One log, shaped like an eth\_getLogs entry

Store as your last processed block

true when a reorg reverses this log

All of a block's matching logs arrive together. alloy buffers 16 notifications per subscription by
default, so the Rust example sets a larger `channel_size`. When a subscriber falls further behind
than its buffer, `recv` returns `Lagged` with the number of skipped logs. Keep receiving, and
backfill the skipped logs with `eth_getLogs` as described in
[Recover after a disconnect](#recover-after-a-disconnect).

## Supported subscriptions

| Subscription             | Use it for                                                 |
| ------------------------ | ---------------------------------------------------------- |
| `newHeads`               | New block headers.                                         |
| `logs`                   | Logs matching an address and topic filter.                 |
| `newPendingTransactions` | Pending transaction hashes when available for the network. |
| `syncing`                | Node sync status updates.                                  |

## Recover after a disconnect

*Blocks N+2 and N+3 were produced while the socket was down, and a new subscription only delivers events from N+4 onward. One bounded eth_getLogs request fills the gap; deduplicate by log identity where the ranges meet.*

- Processed: N, N+1.
- Disconnected: N+2, N+3 missed.
- Resubscribed: events resume at N+4.
- Backfill: `eth_getLogs` fromBlock N+2 · toBlock N+3.

1. Store the last processed block and log identity as you handle each notification.
2. Reconnect with exponential backoff after a disconnect.
3. Resubscribe with the same filter.
4. Backfill with `eth_getLogs` from the block after the last one you processed up to the first
block the new subscription delivers.
5. Deduplicate by `(blockHash, transactionHash, logIndex)` where the backfill and the live stream
overlap.
6. Treat logs with `removed: true` as reversals. See [Retries and reorgs](./retries-and-reorgs).

The backfill is an ordinary HTTPS request. This one reads a single block of USDC `Transfer` logs:

Prerequisites

1. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

[Example project](/examples/rpc.guides.fetch-logs.sh-1.tar.gz)

```sh
# Block numbers are hex quantities: 0x112a882-0x112a887 is blocks 18,000,002-18,000,007.
# The topic is keccak256("Transfer(address,address,uint256)"), the Transfer event signature.
curl --fail-with-body --silent --show-error "https://rpc.graphops.xyz/v1/evm/1" \
  -H "Authorization: Bearer ${GRAPHOPS_API_KEY}" \
  -H "Content-Type: application/json" \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getLogs",
    "params": [
      {
        "fromBlock": "0x112a882",
        "toBlock": "0x112a887",
        "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "topics": [
          "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
        ]
      }
    ]
  }'

```

Output

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000e673bda19a529d9ff13aeddae0e08c0fda8b5488",
        "0x00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000401332c0",
      "blockHash": "0x5b94c39ad7eecbf043f62a4a76c5abee87195207df98ae16eb3f289b2267f141",
      "blockNumber": "0x112a882",
      "blockTimestamp": "0x64ea26a7",
      "transactionHash": "0x29ec08dc5eed0e1cd411b29c52607661155087ffa107bae7f5e4a79f5306be1d",
      "transactionIndex": "0x2b",
      "logIndex": "0xac",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a40bb1c47f6dd27142a2bd7c93bfa98db9d1f5c5",
        "0x000000000000000000000000b4e16d0168e52d35cacd2c6185b44281ec28c9dc"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000011348e5d",
      "blockHash": "0x5b94c39ad7eecbf043f62a4a76c5abee87195207df98ae16eb3f289b2267f141",
      "blockNumber": "0x112a882",
      "blockTimestamp": "0x64ea26a7",
      "transactionHash": "0xa8b07b56f7bb4ea52eecf5a125c75f143955a8e57e1ea17d2d8a48830e7d67db",
      "transactionIndex": "0x71",
      "logIndex": "0x13b",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000180cd4303582d348a54fcb0436d5665f082a23d1",
        "0x000000000000000000000000a9d1e08c7793af67e9d92fe308d5697fb81d3e43"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000aad0a340",
      "blockHash": "0x90c06a9fad66de217ce5862a92a2d45a8f42f9abf8ec17d5bfb85ffdc7836ca4",
      "blockNumber": "0x112a883",
      "blockTimestamp": "0x64ea26b3",
      "transactionHash": "0x05c9c59145387faa91370e56d717d42856bd20f8f19306814d5b7afbe837efe3",
      "transactionIndex": "0x66",
      "logIndex": "0xde",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001c727a55ea3c11b0ab7d3a361fe0f3c47ce6de5d",
        "0x000000000000000000000000c3dcc088aef4373e665b00fc8be45a4b6a4b24a6"
      ],
      "data": "0x000000000000000000000000000000000000000000000000000000000686bcda",
      "blockHash": "0x90c06a9fad66de217ce5862a92a2d45a8f42f9abf8ec17d5bfb85ffdc7836ca4",
      "blockNumber": "0x112a883",
      "blockTimestamp": "0x64ea26b3",
      "transactionHash": "0xeb8505dd3dc2964c1b43ed40371fb9c907b751ccb9294b99db032270889edc42",
      "transactionIndex": "0x72",
      "logIndex": "0xe6",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000000000000000000000000000000000000000000000",
        "0x00000000000000000000000043954785980c50768373dc1dafd7ba3a2052036f"
      ],
      "data": "0x000000000000000000000000000000000000000000000000000000e8d433aa6e",
      "blockHash": "0x7f7889c3686d7f560dd690aeb2a10b49e3a76844543cf78cc0dfe4687e2985d2",
      "blockNumber": "0x112a884",
      "blockTimestamp": "0x64ea26bf",
      "transactionHash": "0xb2c1d8c8e7989adab51dafdc9be24fd05243342b8d08828c4325662de629c690",
      "transactionIndex": "0x48",
      "logIndex": "0xbf",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000c880d8be4e94f644f1daa7d3558b50ff5a1c2db7",
        "0x000000000000000000000000ae2d4617c862309a3d75a0ffb358c7a5009c673f"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000002e90edd000",
      "blockHash": "0x127c6b9794874d7011770b3aa2a0a640e1db201c2d677d01b2b3b19e7ad427c7",
      "blockNumber": "0x112a885",
      "blockTimestamp": "0x64ea26cb",
      "transactionHash": "0x1691b8e89e13f483c549d9b61efbc54ecc54015b8186726911c8458f0993e13d",
      "transactionIndex": "0x1e",
      "logIndex": "0x40",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000b86fc5e985facdcae6034beefc6cbdcd8bbd8cb4",
        "0x00000000000000000000000027f713adefc708469d826ab8f5b1e4672f1a070e"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000059682f00",
      "blockHash": "0x127c6b9794874d7011770b3aa2a0a640e1db201c2d677d01b2b3b19e7ad427c7",
      "blockNumber": "0x112a885",
      "blockTimestamp": "0x64ea26cb",
      "transactionHash": "0x440106b494b7eb657d19e5f82a164ce4cc62e5252058fab5fb4ee6b92600543c",
      "transactionIndex": "0x6d",
      "logIndex": "0xcb",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000b4eae88d1643e172518dde0ef213c20628798c65",
        "0x00000000000000000000000038c5a4f22e2e290ba9bbb9e3d9aaf8582f79f4d1"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000006b78840",
      "blockHash": "0xdb63e26b655ad31d60b2173c02127180ed46b28506f785a2682e058ca61afdc1",
      "blockNumber": "0x112a887",
      "blockTimestamp": "0x64ea26e3",
      "transactionHash": "0x21d8e836f79606db39fcd51f7e563ea9c12cfb7a2bb3e36f23f4eb89b93045ea",
      "transactionIndex": "0x1f",
      "logIndex": "0x5e",
      "removed": false
    },
    {
      "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000579752cff8fee7af09446b2133ee2f9ff10c4fbf",
        "0x0000000000000000000000001715a3e4a142d8b698131108995174f37aeba10d"
      ],
      "data": "0x000000000000000000000000000000000000000000000000000000001d0221cd",
      "blockHash": "0xdb63e26b655ad31d60b2173c02127180ed46b28506f785a2682e058ca61afdc1",
      "blockNumber": "0x112a887",
      "blockTimestamp": "0x64ea26e3",
      "transactionHash": "0xd78a180e669534a650d842f13d032610e29bf4a7731fb90a6dff73d752ac049c",
      "transactionIndex": "0x57",
      "logIndex": "0xb3",
      "removed": false
    }
  ]
}
```

Every matching log in the requested block range

USDC contract

Transfer event signature

Transfer amount: 1,075,000,000 base units, 1,075 USDC

Block in decimal: 18,000,002

## Next steps

* [Retries and reorgs](./retries-and-reorgs): Reverse logs from reorganized blocks and retry failed requests safely.
* [Authentication](../authentication): Protect route-token URLs or send the key in a header instead.
* [Supported methods](../methods#websocket-subscriptions): Check `eth_subscribe` types and parameters.