TriportRPC

Bor pending-transaction WebSocket firehose

GEThttps://api.triport.io/v1/polygon/firehose/mempool/connect-info

Streams Polygon pending (mempool) transactions in real time over a signed WebSocket connection, before they are mined into a block.

Polygonbusiness tier; RPS-per-tier with burst (×2 multiplier) — no daily cap

This channel is the live Polygon pending-transaction (mempool) firehose. Once connected, the server pushes newPendingTransactions notifications as transactions enter the node mempool — before they are included in a block. Use it for mempool monitoring, pre-confirmation transaction tracking, MEV/orderflow analysis, and front-running detection dashboards. A single connection sees a baseline throughput of roughly 32–37 tx/s.

You do not connect to this endpoint directly with your API key. First call GET /v1/polygon/firehose/mempool/connect-info to obtain an already-signed wss:// URL and a short-lived token. Open the WebSocket to that URL, then send token as the first frame on the new connection. The token expires at expires_at, so fetch fresh connect-info immediately before connecting and whenever a connection drops.

The firehose is the highest-tier Polygon product surface and requires the business tier. Lower-tier keys are rejected at the connect-info step with 403 tier_insufficient and, if a stale or under-privileged token reaches the socket, with a 4003 close. The channel accepts subscribe-only traffic: only eth_subscribe / eth_unsubscribe JSON-RPC frames are allowed — any other method (e.g. eth_call, eth_sendRawTransaction) terminates the connection.

Parameters

There are no path or query parameters on the WebSocket itself — the signed url returned by connect-info already carries everything needed to route and authorize the upgrade.

Connection framesobject
eth_subscribe paramsobject

Response

Subscribe acknowledgement (server → client):

Pending-transaction notifications (default tx-hash mode):

{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "subscription": "0x9cef478923d7f1b2c84e1d0a3f6b7c89",
    "result": "0x3b1e8c2f9a4d77e0c1ad55f4b9e2c10f8d6a2b3c4e5f60718293a4b5c6d7e8f9"
  }
}

Full-body mode (includeFullTx: true):

{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "subscription": "0x9cef478923d7f1b2c84e1d0a3f6b7c89",
    "result": {
      "hash": "0x3b1e8c2f9a4d77e0c1ad55f4b9e2c10f8d6a2b3c4e5f60718293a4b5c6d7e8f9",
      "from": "0x6f4e8b2a1c3d5e7f90a1b2c3d4e5f60718293a4b",
      "to": "0x0000000000000000000000000000000000001010",
      "gas_price_wei": "30000000000",
      "max_fee_per_gas_wei": "45000000000",
      "max_priority_fee_per_gas_wei": "30000000000",
      "nonce": 42
    }
  }
}
jsonrpcstring
Always "2.0".
methodstring
"eth_subscription" on pushed notifications.
params.subscriptionstring
Hex subscription id (matches the result from the ack).
params.resultstring | object
Tx hash (default), or the full pending-tx body when includeFullTx=true.
params.result.hashstring
Transaction hash.
params.result.fromstring
Sender address.
params.result.tostring | null
Recipient address; null for contract-creation.
params.result.gas_price_weistring
Legacy gas price, in wei.
params.result.max_fee_per_gas_weistring
EIP-1559 max fee per gas, in wei.
params.result.max_priority_fee_per_gas_weistring
EIP-1559 priority fee per gas, in wei.
params.result.nonceinteger
Sender nonce.

Errors

The server MAY send a WSErrorFrame ({"error": "...", "message": "..."}) immediately before closing with one of the canonical close codes:

CodeMeaningWhen it happens
4001unauthorizedFirst-frame token is missing, invalid, or expired. Re-fetch connect-info and reconnect.
4003forbiddenTier insufficient for the firehose, or a non-subscribe method (e.g. eth_call) was sent.
4029rate_limitedSustained message/connection rate exceeded for the tier. Honour retry_after_sec before reconnecting.
4030trial_expiredThe free-trial period for the key has ended.

Connect-info pre-flight errors (401 / 403 / 429) are returned by /v1/polygon/firehose/mempool/connect-info before any socket is opened. All bodies use the shared envelope (error, message, request_id) — see errors.md for the full schema.

Examples

JavaScript (fetch)

const res = await fetch(
  "https://api.triport.io/v1/polygon/firehose/mempool/connect-info",
  { headers: { Authorization: `Bearer ${process.env.TRIPORT_API_KEY}` } }
);
if (!res.ok) throw new Error(`connect-info failed: ${res.status}`);
const info = await res.json();


const ws = new WebSocket(info.url);
ws.onopen = () => {
  ws.send(info.token); // token as the FIRST frame
  ws.send(JSON.stringify({
    jsonrpc: "2.0", id: 1,
    method: "eth_subscribe", params: ["newPendingTransactions"],
  }));
};
ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data);
  if (msg.method === "eth_subscription") {
    console.log("pending tx:", msg.params.result); // tx hash (default mode)
  }
};
ws.onclose = (ev) => {
  if (ev.code === info.close_codes.unauthorized) {
    // token expired — re-request connect-info and reconnect
  }
};

TypeScript SDK (@triport/sdk)

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


const client = new Triport({ apiKey: process.env.TRIPORT_API_KEY! });


// connectInfo() + connect() handle the signed URL and first-frame token for you.
const info = await client.polygon.firehose.mempool.connectInfo();
const stream = await client.polygon.firehose.mempool.connect(info);


for await (const tx of stream) {
  console.log("pending tx:", tx.hash);
}

Python (triport-sdk)

import os
from triport import Triport


client = Triport(api_key=os.environ["TRIPORT_API_KEY"])


info = client.polygon.firehose.mempool.connect_info()
with client.polygon.firehose.mempool.connect(info) as stream:
    for tx in stream:
        print("pending tx:", tx["hash"])

Notes

  • Two-step connect. Always call /v1/polygon/firehose/mempool/connect-info first; the signed url and token are short-lived and must not be cached across reconnects.
  • Token is the first frame. Send the token string before any subscribe frame, or the connection closes with 4001.
  • Subscribe-only. Only eth_subscribe / eth_unsubscribe are accepted (for newPendingTransactions). Any other JSON-RPC method closes the connection.
  • Pending ≠ confirmed. These transactions are not yet mined and may be dropped or replaced — handle re-orgs and replacements on the consumer side.
  • No daily cap. Rate limiting is RPS-per-tier with a burst multiplier; there is no daily quota.
  • Related: the logs firehose at /v1/polygon/firehose/logs/connect-info (pro tier), and the standard Polygon pub/sub channel for newHeads / logs / syncing subscriptions.