TriportRPC

eth_sendRawTransaction

POSThttps://api.triport.io/v1/polygon/rpc

Broadcasts a signed, RLP-encoded transaction to the Polygon mempool and returns its transaction hash.

Polygonpolygon_send_txFree tier and up — free 3 rps · basic 5 rps · pro 30 rps · business 80 rps (category polygon_send_tx)

eth_sendRawTransaction submits an already-signed transaction to Polygon mainnet for inclusion in a block. You sign the transaction locally with your private key, RLP-encode it, hex-encode the result, and pass that single 0x-prefixed hex string as the only parameter. Triport never sees or holds your key — only the signed payload.

On success the method returns the transaction hash immediately. The hash is returned as soon as the transaction is accepted into the mempool; it does not mean the transaction has been mined. Polygon's Bor consensus produces blocks roughly every ~2 seconds, so poll eth_getTransactionReceipt — or the transaction-by-hash lookups — with the returned hash to confirm inclusion and read the final status.

This is the only state-changing method on the Polygon eth surface, and it sits in its own polygon_send_tx rate-limit category with markedly lower limits than read methods (3 rps on free vs. 15 rps for reads). Budget your send rate accordingly and back off on -32003. The method is available from the free tier upward — no paid tier is required to broadcast transactions.

Gotchas

  • Use Polygon's chain ID. The transaction must be signed with EIP-155 replay protection using chain ID 0x89 (137). A transaction signed for another chain (e.g. Ethereum mainnet, 0x1) is rejected with -32000 invalid sender before it ever reaches the mempool, because the recovered signer does not match.
  • Replay protection is mandatory. Without EIP-155 binding to 0x89, a Polygon transaction could also be valid on other EVM chains — a replay-attack vector. Always sign with the correct chain ID.
  • Idempotent re-broadcast. Re-submitting the same signed transaction (same hash) is safe. Depending on the upstream node it returns either the same hash again or -32000 already known. Treat both outcomes as success.

Parameters

A single positional parameter:

signedTransactionDatastring (0x-prefixed hex)required
The signed transaction, RLP-encoded and hex-encoded. Produced by your signing library (e.g. ethers, web3.py, viem). Must carry an EIP-155 signature over chain ID 0x89 (137). Supports legacy and typed (EIP-1559 / EIP-2930) transactions.

Response

Response fields

FieldTypeDescription
jsonrpcstringAlways "2.0".
idnumber | stringEchoes the request id.
resultstring (0x-prefixed hex)The 32-byte transaction hash. Use it to poll for the receipt and confirm inclusion.

Errors

On failure the response carries an error object instead of result, with extra context under error.data. See the shared errors reference for the full envelope and the canonical meaning of each platform code.

CodeMeaningWhen it happens
-32000execution error (passthrough)The network rejected the transaction — e.g. invalid sender (wrong chain ID / bad signature), nonce too low, insufficient funds, gas price too low, or already known. The message carries the node's reason. already known on a re-broadcast is harmless.
-32001trial_expiredThe free-trial period for this key has ended (HTTP 401). Upgrade to a paid tier to keep broadcasting.
-32002tier_insufficientThe key's tier is below what the method requires. eth_sendRawTransaction is available from the free tier, so this appears only if the key's scopes are restricted. Carries data.required_tier / data.upgrade_url.
-32003rate_limitedSustained sends exceeded your tier's polygon_send_tx rps (HTTP 429). Honour Retry-After / error.data.retry_after_sec. Limits are low here: 3 rps free, 5 basic, 30 pro, 80 business.
-32004subscription_expiredA previously active paid subscription has lapsed; renew to restore access.
-32005unauthorizedMissing, invalid, or revoked API key.
-32601method_unknownThe method name is misspelled or not part of the Polygon product. Carries data.chain and data.method.

rate_limited (-32003)

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32003,
    "message": "Rate limit exceeded: 3 RPS sustained on polygon_send_tx (free tier)",
    "data": {
      "current_tier": "free",
      "category": "polygon_send_tx",
      "limit_rps": 3,
      "burst_capacity": 6,
      "retry_after_sec": 1
    }
  }
}

burst_capacity is always 2 × limit_rps. The response also carries Retry-After and X-RateLimit-* headers — see Errors. Rate limiting is enforced per-second per tier with burst headroom; there is no daily quota.

Examples

JavaScript (fetch)

const signedTx = "0xf86c098504a817c8..."; // signed for chainId 0x89, produced by your signer


const res = await fetch("https://api.triport.io/v1/polygon/rpc", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TRIPORT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "eth_sendRawTransaction",
    params: [signedTx],
  }),
});


const body = await res.json();
if (body.error) {
  if (body.error.code === -32003) {
    const wait = Number(res.headers.get("Retry-After") ?? body.error.data.retry_after_sec);
    await new Promise((r) => setTimeout(r, wait * 1000)); // then retry
  } else if (/already known/i.test(body.error.message)) {
    console.log("already broadcast — safe to ignore");
  } else {
    throw new Error(body.error.message); // e.g. invalid sender, nonce too low
  }
} else {
  console.log("tx hash:", body.result);
}

TypeScript SDK (@triport/sdk)

import { Triport, RateLimitedError } from "@triport/sdk";
import { Wallet, Transaction } from "ethers";


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


// Sign locally for Polygon (chainId 137 / 0x89)
const wallet = new Wallet(process.env.PRIVATE_KEY!);
const signedTx = await wallet.signTransaction({
  chainId: 137,
  to: "0x742d35Cc6634C0532925a3b844Bc9e7595f06b8b",
  value: 10n ** 18n,
  nonce: 9,
  gasLimit: 21000,
  gasPrice: 20_000_000_000n,
});


try {
  const txHash = await triport.polygon.rpc("eth_sendRawTransaction", [signedTx]);
  console.log("tx hash:", txHash);
} catch (err) {
  if (err instanceof RateLimitedError) {
    await new Promise((r) => setTimeout(r, err.retryAfterSec * 1000)); // then retry
  } else {
    throw err;
  }
}

Python (triport-sdk)

import os, time
from triport import Triport
from triport.errors import RateLimitedError
from eth_account import Account
from eth_account.datastructures import SignedTransaction


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


# Sign locally for Polygon (chainId 137 / 0x89)
signed: SignedTransaction = Account.sign_transaction(
    {
        "chainId": 137,
        "to": "0x742d35Cc6634C0532925a3b844Bc9e7595f06b8b",
        "value": 10**18,
        "nonce": 9,
        "gas": 21000,
        "gasPrice": 20_000_000_000,
    },
    os.environ["PRIVATE_KEY"],
)


try:
    tx_hash = triport.polygon.rpc(
        "eth_sendRawTransaction",
        [signed.rawTransaction.hex()],
    )
    print("tx hash:", tx_hash)
except RateLimitedError as e:
    time.sleep(e.retry_after_sec)  # then retry

Notes

  • The hash is not confirmation. A returned hash means accepted into the mempool, not mined. Poll for the transaction receipt until one appears, then check its status field. Polygon's ~2-second block time means confirmation is usually quick, but reorgs near the chain head are possible — wait for a few confirmations before treating a transfer as final.
  • Sign for chain ID 0x89. Building and signing for the wrong chain ID is the most common cause of -32000 invalid sender. Set chainId: 137 in your signer.
  • Idempotent re-broadcast. Re-submitting the same signed transaction usually yields the same hash; some nodes return an already known execution error (-32000) instead, which is harmless.
  • Public mempool exposure. Transactions broadcast here enter the public pending pool and are visible to other participants before inclusion, which exposes them to front-running. For latency-sensitive or MEV-sensitive sends, account for this when setting gas and slippage.
  • Low send budget. The polygon_send_tx category caps sends well below read methods (3 rps free). For sustained high-throughput sending, upgrade to a tier with a higher polygon_send_tx rps limit.
  • Related: simulate a call first with eth_call, size gas with eth_estimateGas, read fee data with eth_gasPrice / eth_feeHistory. See also Errors · Rate limits · Authentication.