TriportRPC

Ethereum Pub/Sub WebSocket — /ws/eth

Subscribe over WebSocket to real-time Ethereum events — pending transactions, filtered logs, new block headers, and node sync state — using the standard `eth_subscribe` / `eth_unsubscribe` JSON-RPC shape.

Ethereum— (gated by subscription type → tier; see below)Per subscription type: newPendingTransactions free · logs basic · newHeads / syncing pro

/ws/eth is the Ethereum JSON-RPC Pub/Sub channel. Open a single WebSocket connection, send an eth_subscribe request naming one of four subscription types, and the server replies with a hex-encoded subscription id. From then on the server pushes eth_subscription notification frames carrying that id and the event payload until you send eth_unsubscribe (or the socket closes).

You can hold multiple subscriptions on one connection; each notification frame identifies its source via params.subscription, so match incoming events to the id you stored at subscribe time.

The four subscription types unlock at different tiers. Attempting to subscribe to a type above your plan returns a forbidden error frame followed by a WS close 4003 — the frame includes current_tier, required_tier, and an upgrade_url so you can prompt for an upgrade without a second call.

Parameters

The eth_subscribe request params array holds the subscription type in params[0] and an optional, type-specific filter/option object in params[1].

newPendingTransactionsobject
includeFullTxbooleanoptional
When true, each notification carries the full transaction body. Defaults to false (tx hash only).
logsobject
addressstring | string[]optional
One contract address, or an array of addresses, to match.
topicsarrayoptional
Up to 4 indexed-topic slots. Each slot is a topic string, an array of strings (OR-match), or null (wildcard for that position).

Response

Subscribe acknowledgementresult is the hex subscription id to keep:

Notification (newPendingTransactions, hash mode):

{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "subscription": "0x9cef478923ff08bf67fde6c64013158d",
    "result": "0x68e63ee5b6f7e2b2e9e1cf0d2f5cda0c4f3a9b1d7e8c6a5b4c3d2e1f0a9b8c7d"
  }
}

Notification (newHeads):

{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "subscription": "0x1a2b3c4d5e6f70819a0b1c2d3e4f5061",
    "result": {
      "number": "0x12a4f8b",
      "hash": "0x4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c",
      "parentHash": "0x9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f",
      "nonce": "0x0000000000000000",
      "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
      "logsBloom": "0x00000000000000000000000000000000",
      "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
      "stateRoot": "0xdeadbeef00000000000000000000000000000000000000000000000000000000",
      "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
      "miner": "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5",
      "difficulty": "0x0",
      "extraData": "0x6265617665726275696c642e6f7267",
      "gasLimit": "0x1c9c380",
      "gasUsed": "0x10a3b2f",
      "timestamp": "0x66f4c3a8",
      "baseFeePerGas": "0x53724e1a"
    }
  }
}

Notification (syncing, false once fully synced):

{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "subscription": "0x7f6e5d4c3b2a19080716253443526170",
    "result": false
  }
}
jsonrpcstring
Always "2.0".
idinteger | string
Echoes the request id.
resultstring
Hex-encoded subscription id — pass to eth_unsubscribe and match against incoming params.subscription.

Errors

The server may send an application-level error frame immediately before closing the socket with one of the canonical close codes.

Close codeerrorWhen it happens
4001unauthorizedMissing or invalid credentials on the upgrade / auth frame.
4003forbiddenSubscription type requires a higher tier, or the method is unknown. Frame carries current_tier, required_tier, method, and upgrade_url.
4029rate_limitedPer-tier RPS exceeded. Frame carries retry_after_sec and limit_rps.
4030trial_expiredTrial period has ended; frame carries upgrade_url.

Example error frame (sent just before a 4003 close):

{
  "error": "forbidden",
  "message": "subscription type 'newHeads' requires the pro tier",
  "current_tier": "basic",
  "required_tier": "pro",
  "method": "newHeads",
  "category": "eth_ws_pubsub",
  "upgrade_url": "https://triport.io/upgrade?tier=pro"
}

See errors.md for the full error envelope and shared close-code reference.

Examples

JavaScript (fetch)

WebSockets are not opened with fetch; use the browser/Node WebSocket API:

const ws = new WebSocket("wss://ws.triport.io/ws/eth", {
  headers: { Authorization: `Bearer ${process.env.TRIPORT_API_KEY}` },
});


const subs = new Map(); // subscription id -> type


ws.addEventListener("open", () => {
  ws.send(JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "eth_subscribe",
    params: ["newHeads"],
  }));
});


ws.addEventListener("message", (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.id === 1 && msg.result) {
    subs.set(msg.result, "newHeads"); // store the hex id
  } else if (msg.method === "eth_subscription") {
    console.log("block", msg.params.result.number, "from", msg.params.subscription);
  }
});

TypeScript SDK (@triport/sdk)

import { TriportWS } from "@triport/sdk";


const ws = new TriportWS({ apiKey: process.env.TRIPORT_API_KEY! });
const eth = await ws.eth.connect();


// logs for USDT Transfer events
const sub = await eth.subscribe("logs", {
  address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
  topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],
});


sub.on("data", (log) => console.log(log.transactionHash, log.data));


// later
await eth.unsubscribe(sub.id);

Python (triport-sdk)

import os
from triport import TriportWS


ws = TriportWS(api_key=os.environ["TRIPORT_API_KEY"])


with ws.eth() as eth:
    sub = eth.subscribe("newPendingTransactions", {"includeFullTx": False})
    for tx_hash in sub:
        print("pending:", tx_hash)
        # eth.unsubscribe(sub.id) to stop

Notes

  • One id per subscription. Store the hex result from each acknowledgement; it is the only way to correlate notifications (params.subscription) and to eth_unsubscribe later.
  • logs topic slots. topics accepts up to four positions. Use null in a slot to wildcard it, or an array of strings to OR-match several values in that position.
  • newPendingTransactions volume. Hash-only mode (the default) is far lighter than includeFullTx=true; enable full bodies only when you actually need the decoded transaction.
  • Tier gating is per subscription type, not per connection — a free key can open newPendingTransactions but will be closed with 4003 if it tries newHeads.
  • Polygon exposes the same four subscription types on /ws/polygon. Solana pub/sub lives at /ws/sol. See the streaming overview for all channels.