Everything you need to send your first request.
Authentication, request format, limits and error codes for the Iteradian gateway, with copy-paste examples in cURL, JavaScript, Python, Go, Rust, C#, Java and PHP, and setup for ethers, viem, web3.py and @solana/web3.js.
What Iteradian is
Iteradian is a multi-chain RPC gateway. You create an API key, send standard JSON-RPC 2.0 requests over HTTPS, and the gateway forwards each one to a healthy node for the network you named, failing over to another node when one does not answer. Keys, usage, request logs, alerts, your team and billing are managed in the dashboard or through the management API.
| Host | What it is |
|---|---|
https://api.iteradian.com | RPC gateway. Send your JSON-RPC requests here. |
https://api.iteradian.com/api/v1 | Management API: accounts, organizations, API keys, usage, billing. |
https://app.iteradian.com | Dashboard: sign up, sign in and manage everything. |
Send your first request
1. Create an account
Sign up with an email and password, or with Google or GitHub. Every account gets a personal organization, which starts on a 7-day trial of Developer RPC.
2. Create an API key
In the dashboard, open Organization → API Keys and create a key. The full key is shown once, so put it straight into a secret manager or an environment variable. The examples on this page read it from
ITERADIAN_API_KEY.3. Call the gateway
POST a JSON-RPC 2.0 body to the network’s URL with the key in the
X-Api-Keyheader.cURL curl -sS https://api.iteradian.com/rpc/v1/eth-mainnet \ -H "Content-Type: application/json" \ -H "X-Api-Key: $ITERADIAN_API_KEY" \ -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' # {"jsonrpc":"2.0","id":1,"result":"0x1502f8a"}4. Read the response
The body is the node’s JSON-RPC 2.0 response, passed through unchanged. For
eth_blockNumberthe result is the latest block number as a hex string. A 4xx or 5xx status means the gateway stopped the call — see Errors and retries.
Headers, body and batching
Every call is POST https://api.iteradian.com/rpc/v1/{network} with a standard JSON-RPC 2.0 body. {network} is a slug from the networks table — the path is always /rpc/v1/ followed by the slug.
| Item | Value |
|---|---|
| Authentication | X-Api-Key: <key> or Authorization: Bearer <key> |
| Content type | Content-Type: application/json |
| Request body limit | 1 MB |
| Upstream timeout | 30 seconds |
| Transport | HTTPS, plus WebSocket at wss://rpc.iteradian.com/ws/v1/{network}. |
X-Api-Key is the preferred header and wins when both are sent. Authorization: Bearer <key> takes the same API key — never a dashboard login token.
curl -sS https://api.iteradian.com/rpc/v1/eth-mainnet \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ITERADIAN_API_KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'Batching
Send a JSON array of requests. Responses can come back in any order, so match them by id. A batch of N calls counts as N requests against the rate limit and the monthly quota: batching saves round trips, not allowance.
curl -sS https://api.iteradian.com/rpc/v1/eth-mainnet \
-H "Content-Type: application/json" \
-H "X-Api-Key: $ITERADIAN_API_KEY" \
-d '[{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]},
{"jsonrpc":"2.0","id":2,"method":"eth_chainId","params":[]}]'
# [{"jsonrpc":"2.0","id":2,"result":"0x1"},{"jsonrpc":"2.0","id":1,"result":"0x1502f8a"}]
# Responses can arrive in any order: match them by id. This batch counts as 2 requests.Which methods work
Any JSON-RPC method is forwarded to the node; there is no method blocklist. Whether trace_*, debug_* or archive queries work depends on the node that serves the request, so test them before you depend on them.
Transaction submissions (eth_sendRawTransaction, eth_sendTransaction, sendTransaction, author_submitExtrinsic) go to one node and are never retried or replayed by the gateway. Every other call fails over across up to 3 nodes automatically.
Which networks are up
GET https://api.iteradian.com/rpc/v1/networks lists the networks available right now — only those with a healthy node. It needs no API key.
# No API key needed. Lists networks with a healthy node right now.
curl -sS https://api.iteradian.com/rpc/v1/networksExamples by language
The same eth_blockNumber call in each language, using only the standard HTTP client where one exists.
// Node.js 18+ (built-in fetch)
const res = await fetch("https://api.iteradian.com/rpc/v1/eth-mainnet", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.ITERADIAN_API_KEY,
},
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] }),
});
const body = await res.json();
if (!res.ok) throw new Error(`HTTP ${res.status}: ${JSON.stringify(body)}`);
if (body.error) throw new Error(`RPC error ${body.error.code}: ${body.error.message}`);
console.log(BigInt(body.result));import os
import requests
res = requests.post(
"https://api.iteradian.com/rpc/v1/eth-mainnet",
headers={"X-Api-Key": os.environ["ITERADIAN_API_KEY"]},
json={"jsonrpc": "2.0", "id": 1, "method": "eth_blockNumber", "params": []},
timeout=35,
)
res.raise_for_status()
body = res.json()
if "error" in body:
raise RuntimeError(body["error"])
print(int(body["result"], 16))package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body := []byte(`{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}`)
req, err := http.NewRequest("POST", "https://api.iteradian.com/rpc/v1/eth-mainnet", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Api-Key", os.Getenv("ITERADIAN_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.StatusCode, string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] },
// serde_json = "1", tokio = { version = "1", features = ["full"] }
use serde_json::{json, Value};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let key = std::env::var("ITERADIAN_API_KEY")?;
let body: Value = reqwest::Client::new()
.post("https://api.iteradian.com/rpc/v1/eth-mainnet")
.header("X-Api-Key", key)
.json(&json!({ "jsonrpc": "2.0", "id": 1, "method": "eth_blockNumber", "params": [] }))
.send()
.await?
.error_for_status()?
.json()
.await?;
println!("{}", body["result"]);
Ok(())
}using System.Net.Http;
using System.Text;
using var http = new HttpClient();
using var req = new HttpRequestMessage(HttpMethod.Post, "https://api.iteradian.com/rpc/v1/eth-mainnet");
req.Headers.Add("X-Api-Key", Environment.GetEnvironmentVariable("ITERADIAN_API_KEY"));
req.Content = new StringContent(
"{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_blockNumber\",\"params\":[]}",
Encoding.UTF8,
"application/json");
using var res = await http.SendAsync(req);
Console.WriteLine($"{(int)res.StatusCode} {await res.Content.ReadAsStringAsync()}");import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class BlockNumber {
public static void main(String[] args) throws Exception {
HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.iteradian.com/rpc/v1/eth-mainnet"))
.header("Content-Type", "application/json")
.header("X-Api-Key", System.getenv("ITERADIAN_API_KEY"))
.POST(HttpRequest.BodyPublishers.ofString(
"{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_blockNumber\",\"params\":[]}"))
.build();
HttpResponse<String> res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.statusCode() + " " + res.body());
}
}<?php
$ch = curl_init("https://api.iteradian.com/rpc/v1/eth-mainnet");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: " . getenv("ITERADIAN_API_KEY"),
],
CURLOPT_POSTFIELDS => json_encode([
"jsonrpc" => "2.0", "id" => 1, "method" => "eth_blockNumber", "params" => [],
]),
]);
$body = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), " ", $body["result"] ?? json_encode($body), PHP_EOL;Using existing Web3 libraries
Libraries that speak JSON-RPC over HTTP work unchanged: give them the network URL and add the X-Api-Key header.
// ethers v6
import { ethers } from "ethers";
const req = new ethers.FetchRequest("https://api.iteradian.com/rpc/v1/eth-mainnet");
req.setHeader("X-Api-Key", process.env.ITERADIAN_API_KEY);
const provider = new ethers.JsonRpcProvider(req);
console.log(await provider.getBlockNumber());// viem
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({
chain: mainnet,
transport: http("https://api.iteradian.com/rpc/v1/eth-mainnet", {
fetchOptions: { headers: { "X-Api-Key": process.env.ITERADIAN_API_KEY } },
}),
});
console.log(await client.getBlockNumber());// @solana/web3.js
import { Connection } from "@solana/web3.js";
const connection = new Connection("https://api.iteradian.com/rpc/v1/sol-mainnet", {
httpHeaders: { "X-Api-Key": process.env.ITERADIAN_API_KEY },
});
console.log(await connection.getSlot());# web3.py
import os
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(
"https://api.iteradian.com/rpc/v1/eth-mainnet",
request_kwargs={"headers": {"X-Api-Key": os.environ["ITERADIAN_API_KEY"]}},
))
print(w3.eth.block_number)Networks and slugs
The slug is the last part of the URL. Slugs are case-insensitive, and an underscore or a space is read as a hyphen. Each network accepts several slugs: examples use the dashboard slug, which is what the app shows, and the aliases work the same way. An unknown slug returns HTTP 400.
This table is the catalogue. A network is served only while it has a healthy node, so check GET https://api.iteradian.com/rpc/v1/networks for what is available right now rather than assuming every row is up.
| Network | Dashboard slug | Also accepted | Chain ID |
|---|---|---|---|
| Ethereum Mainnet | eth-mainnet | ethereum-mainnet | 1 |
| Ethereum Sepolia | eth-testnet | eth-sepolia, ethereum-sepolia | 11155111 |
| Polygon Mainnet | polygon-mainnet | matic-mainnet | 137 |
| Polygon Amoy | polygon-testnet | polygon-amoy, polygon-mumbai | 80002 |
| Arbitrum One | arbitrum-mainnet | arb-mainnet | 42161 |
| OP Mainnet | optimism-mainnet | op-mainnet | 10 |
| Base | base-mainnet | — | 8453 |
| Avalanche C-Chain | avalanche-mainnet | avax-mainnet | 43114 |
| BNB Smart Chain | bsc-mainnet | bnb-mainnet | 56 |
| Fantom Opera | fantom-mainnet | ftm-mainnet | 250 |
| Solana Mainnet Beta | sol-mainnet | solana-mainnet | — |
| Solana Devnet | sol-devnet | solana-devnet | — |
| Bittensor (Finney) | tao-mainnet | bittensor-mainnet | — |
| Bittensor Testnet | tao-testnet | bittensor-testnet | — |
| NEAR Mainnet | near-mainnet | — | — |
| Cosmos Hub | cosmos-mainnet | atom-mainnet | — |
| Lightchain AI Mainnet | lcai-mainnet | lightchain-mainnet | — |
| Lightchain AI Testnet | lcai-testnet | lightchain-testnet | — |
The live listing could not be read when this page was generated, so this table says nothing about current availability.
Limits, quotas and overage
- Limits belong to your organization’s subscription and are shared by all of its API keys. Creating more keys does not add capacity.
- The per-second rate limit is a sliding one-second window. Concurrency is the number of your requests in flight at once.
- The monthly quota runs over your subscription’s billing period, not the calendar month.
- A batch of N calls counts as N requests.
- A key can carry its own rate limit of 1–10,000 requests per second. It can only lower the organization’s limit for that key, never raise it.
On plans with overage enabled, requests past the included allowance keep being served and are billed per 1,000 requests, up to the plan’s overage cap for the period. After the cap, requests get -32007. Owners and admins get an email when overage starts and when the cap is reached.
| Plan | Requests / second | Concurrent | Included / period | Overage |
|---|---|---|---|---|
| Free RPC | 25 | 10 | 3,000,000 | — |
| Developer RPC | 250 | 100 | 25,000,000 | Overage $0.005 per 1,000 requests, capped at $150 per billing period |
| Professional RPC | 500 | 500 | 80,000,000 | Overage $0.003 per 1,000 requests, capped at $350 per billing period |
| Dedicated RPC | Custom | Custom | Unlimited | None — unlimited requests |
Prices and limits read from the control plane on 27 October 2026. Plans priced per contract have their limits set in the contract. Compare plans
Errors and retries
Limit errors are HTTP 429 with a JSON-RPC envelope ({"jsonrpc":"2.0","id":null,"error":{"code":…,"message":…,"data":{…}}}). 400 and 403 are not JSON-RPC envelopes: their body is {"statusCode":…,"message":…,"error":…}. A 200 can still carry the node’s own JSON-RPC error — that is the chain rejecting the call.
| HTTP | Code | Meaning | Retry? |
|---|---|---|---|
| 200 | node’s own | The chain rejected the call (revert, bad params). The node's own JSON-RPC error is passed through unchanged. | No — fix the call. |
| 400 | — | Missing API key, a body that is not JSON-RPC, or an unknown network slug. | No. |
| 403 | — | Invalid, revoked or expired key; IP not on the key's allowlist; network not allowed for this key; organization suspended; no active subscription, or the subscription is past due, canceled or unpaid. | No. |
| 429 | -32005 | Over the per-second rate limit (data.retryAfter seconds, data.allowed, data.cost) or over the concurrency limit (data.inFlight). | Yes, after data.retryAfter seconds. |
| 429 | -32006 | Monthly request quota used up. data.resetsAt is when it resets. | No — not until resetsAt, or upgrade. |
| 429 | -32007 | Overage spend cap reached (data.overageCapUsd). | No — raise the cap or change plan. |
| 503 | -32603 | Every node tried for the network failed. | Yes, with backoff. |
| 503 | — | No nodes are available for the network at all. | Yes, later. |
HTTP/1.1 429 Too Many Requests
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32005,
"message": "…",
"data": { "retryAfter": 1, "allowed": 20, "cost": 1 }
}
}HTTP/1.1 403 Forbidden
{ "statusCode": 403, "message": "…", "error": "Forbidden" }Retrying safely
Retry -32005 after error.data.retryAfter seconds, and 503 with backoff. Never retry -32006 or -32007: they cannot succeed until the quota resets, the cap is raised or the plan changes.
Be careful re-sending a transaction submission: the gateway never replays one, and a failed-looking attempt may still have reached the network. Check for the transaction by hash before sending it again.
// Retry only what can succeed on a second attempt.
const RPC_URL = "https://api.iteradian.com/rpc/v1/eth-mainnet";
async function rpc(payload, attempts = 4) {
for (let attempt = 1; ; attempt++) {
const res = await fetch(RPC_URL, {
method: "POST",
headers: { "Content-Type": "application/json", "X-Api-Key": process.env.ITERADIAN_API_KEY },
body: JSON.stringify(payload),
});
const body = await res.json().catch(() => null);
if (res.ok) return body; // may still carry the node's own error: fix the call, do not retry
const code = body?.error?.code;
const retryable =
(res.status === 429 && code === -32005) || // rate or concurrency limit
res.status === 503; // nodes failed or unavailable
// -32006 (monthly quota) and -32007 (overage cap) can never succeed on retry.
if (!retryable || attempt >= attempts) {
throw new Error(`HTTP ${res.status} ${code ?? ""} ${JSON.stringify(body)}`);
}
const waitSeconds = body?.error?.data?.retryAfter ?? Math.min(2 ** attempt, 30);
await new Promise((r) => setTimeout(r, waitSeconds * 1000));
}
}
console.log(await rpc({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] }));Creating and managing API keys
Create keys in the dashboard (Organization → API Keys) or with the management API. Owners and admins can create, edit, rotate and revoke keys; developers and viewers can see them. Creating a key needs an active or trialing subscription.
A key is itrd_live_ or itrd_test_ followed by 64 hex characters. The full key is shown once — when it is created and when it is rotated. After that only a prefix is visible.
| Option | What it does |
|---|---|
| Name | Required. |
| Environment | live or test. A label for organizing keys — it does not limit which networks the key can call. |
| IP allowlist | Up to 50 IP addresses or CIDR ranges. Requests from anywhere else get 403. |
| Allowed networks | Restricts the key to the networks you pick. Empty means every network. |
| Rate limit | 1–10,000 requests per second. Only ever lowers the organization’s limit for this key. |
| Expiry | Optional. An expired key gets 403. The dashboard offers never, or 30 / 90 / 180 / 365 days. |
Revoking a key is permanent: a revoked key cannot be edited or rotated.
Each key has its own analytics over the last 1d / 7d / 30d / 90d.
Keeping keys safe
- Keep keys on servers. Never ship one in a browser bundle or a mobile app, where anyone can read it out.
- Set an IP allowlist on keys used from servers with fixed addresses.
- Restrict each key to the networks it actually needs.
- Use one key per service, so usage stays separate and one key can be revoked without touching the others.
- Give keys for short-lived jobs an expiry.
Official SDKs
The SDKs cover the management API and RPC calls. Each takes two base URLs — the management API (https://api.iteradian.com/api/v1) and the gateway (https://api.iteradian.com) — and defaults to both. RPC calls go through an rpc group: call, batch and networks.
They retry -32005 and 5xx errors, honouring retryAfter, never retry -32006 or -32007, and never retry transaction submissions.
| Language | Package | Install |
|---|---|---|
| TypeScript / JavaScript | npm · @iteradian-rpc/sdk | npm install @iteradian-rpc/sdk |
| Python | PyPI · iteradian | pip install iteradian |
| C# / .NET | NuGet · Iteradian | dotnet add package Iteradian |
First call
import { IteradianClient } from "@iteradian-rpc/sdk";
const client = new IteradianClient({ apiKey: process.env.ITERADIAN_API_KEY });
const res = await client.rpc.call("eth-mainnet", {
jsonrpc: "2.0",
id: 1,
method: "eth_blockNumber",
params: [],
});
console.log(res.result);import os
from iteradian import IteradianClient
# Synchronous client (built on httpx).
client = IteradianClient(api_key=os.environ["ITERADIAN_API_KEY"])
res = client.rpc.call("eth-mainnet", {
"jsonrpc": "2.0",
"id": 1,
"method": "eth_blockNumber",
"params": [],
})
print(res["result"])using Iteradian;
// .NET 6 and 8.
var client = new IteradianClient(
"https://api.iteradian.com/api/v1",
"https://api.iteradian.com");
client.SetApiKey(Environment.GetEnvironmentVariable("ITERADIAN_API_KEY"));
var res = await client.Rpc.CallAsync("eth-mainnet", new
{
jsonrpc = "2.0",
id = 1,
method = "eth_blockNumber",
@params = Array.Empty<object>(),
});
Console.WriteLine(res?["result"]);Managing your account over HTTP
The management API at https://api.iteradian.com/api/v1 covers what the dashboard does: accounts, organizations, members, API keys, usage, logs, alerts, billing and support. It authenticates with an access token in Authorization: Bearer <accessToken> — not with an API key.
Signing in returns an access token that lasts 15 minutes and a refresh token that lasts 7 days. Refresh tokens are single-use: each refresh returns a new one, so store it every time.
# Sign in — returns accessToken (15 min) and refreshToken (7 days)
curl -sS https://api.iteradian.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"…"}'
# With 2FA on, the first response is {"requires2FA":true}; repeat with "twoFactorCode":"123456".
curl -sS https://api.iteradian.com/api/v1/orgs -H "Authorization: Bearer $ACCESS_TOKEN"
# On 401: refresh (single-use — store the new refreshToken)
curl -sS https://api.iteradian.com/api/v1/auth/refresh \
-H "Content-Type: application/json" -d "{\"refreshToken\":\"$REFRESH_TOKEN\"}"Creating a key
The create body is below. allowedNetworks takes network IDs from GET /networks, not slugs, and unknown fields are rejected.
{ name, environment: "live"|"test", ipAllowlist?: string[],
allowedNetworks?: string[], // network IDs from GET /networks
rateLimit?: number, expiresAt?: ISO date }curl -sS https://api.iteradian.com/api/v1/orgs/$ORG_ID/keys \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"backend-prod","environment":"live","ipAllowlist":["203.0.113.0/24"],"rateLimit":50}'
# The full key is in this response and is never shown again. Unknown fields are rejected.Route reference
Every route is under https://api.iteradian.com/api/v1. There is no public OpenAPI or Swagger page, so this table is the reference.
| Group | Routes |
|---|---|
| Public (no sign-in) | GET /plans, GET /plans/{planId}, GET /health |
| Auth | POST /auth/register, /auth/login, /auth/refresh, /auth/logout, /auth/verify-email, /auth/resend-verification, /auth/forgot-password, /auth/reset-password, /auth/magic-link, /auth/magic-login, /auth/2fa/enable, /auth/2fa/verify, /auth/2fa/disable, /auth/2fa/backup-codes; GET /auth/oauth/{google|github} |
| User | GET/PUT /users/me, PUT /users/me/password, GET /users/me/memberships, DELETE /users/me |
| Organizations | GET/POST /orgs, GET/PUT/DELETE /orgs/{orgId}, GET/POST /orgs/{orgId}/members, PUT/DELETE /orgs/{orgId}/members/{memberId}, POST /orgs/{orgId}/leave, GET /orgs/{orgId}/permissions |
| API keys | GET/POST /orgs/{orgId}/keys, GET/PUT/DELETE /orgs/{orgId}/keys/{keyId} (DELETE = revoke), POST /orgs/{orgId}/keys/{keyId}/rotate, GET /orgs/{orgId}/keys/{keyId}/analytics?timeRange=1d|7d|30d|90d |
| Networks (signed in) | GET /networks, GET /networks/{networkId} |
| Usage and analytics | GET /orgs/{orgId}/usage?from&to, GET /orgs/{orgId}/usage/summary, GET /orgs/{orgId}/dashboard (+ /health, /quick-stats, /request-rate, /error-rate, /latency, /performance) |
| Logs | GET /orgs/{orgId}/logs, /logs/stats, /logs/filters, /logs/{logId} |
| Alerts | GET /orgs/{orgId}/alerts; rules GET/POST /orgs/{orgId}/alerts/rules, GET/PUT/DELETE …/rules/{ruleId}, POST …/rules/{ruleId}/toggle, POST …/rules/seed-defaults; channels GET/POST …/channels, GET/PUT/DELETE …/channels/{channelId}, POST …/channels/{channelId}/test; POST …/alerts/{alertId}/acknowledge, …/resolve |
| Subscription and billing | GET /orgs/{orgId}/subscription, GET …/subscription/preview-change/{planId}, PUT …/subscription/plan (body must include "acceptedTerms": true), POST …/subscription/cancel, POST …/subscription/reactivate, GET …/subscription/invoices; GET /orgs/{orgId}/billing/status, POST …/billing/checkout-session, POST …/billing/portal-session |
| Support | GET/POST /orgs/{orgId}/support/tickets, GET …/tickets/stats, GET …/tickets/{ticketId}, POST …/tickets/{ticketId}/messages, PUT …/tickets/{ticketId}/status |
What the dashboard does
| Area | What you get |
|---|---|
| Overview | Total requests, error rate, average and P95 latency, active keys, health, recent alerts, a request-rate chart and root-cause hints. |
| Usage | Requests over time, by API key, by network and by region, with a daily table. |
| Request logs | Every request, filterable by network, method, status, key and more, with details and stats. Kept for 30 days. |
| Alerts | Rules for high error rate, high latency, rate limit exceeded, quota warning, service down, key expiring and unusual traffic, with severities from info to critical. Delivered by email, webhook or Slack. Rules are evaluated every 5 minutes. |
| Endpoints | Monitoring for the nodes behind your networks. It does not change how requests are routed — routing is automatic. |
| Status | A private health view of your organization’s networks and endpoints. |
| Support | Tickets with a category (general, billing, technical, API keys, endpoints, performance, security, feature request, bug report) and a priority from low to urgent. |
| Billing | Stripe checkout, the Stripe customer portal for payment methods and invoices, plan changes with a proration preview, cancel and reactivate. |
| Account | Profile, avatar (with an optional separate dark-theme avatar), password, two-factor authentication and linked Google or GitHub accounts. |
| SDKs and API guide | An SDKs page and an in-app “Use the API directly” guide. Light, dark and system themes. |
Verifying alert webhooks
Webhook deliveries are signed with an X-Signature-256 header of the form sha256=<HMAC>. Compute the HMAC over the raw request body with the channel’s secret and compare before trusting the payload.
// Node.js — verify an alert webhook before trusting it.
import { createHmac, timingSafeEqual } from "node:crypto";
export function isFromIteradian(rawBody, signatureHeader, secret) {
// Header: X-Signature-256: sha256=<hex HMAC-SHA256 of the raw request body>
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(signatureHeader ?? "");
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Team and roles
Members are added by email and must already have an Iteradian account; they get access immediately. There are no invitation emails or pending invites. Admins can add developers and viewers; only owners can change roles. Anyone can leave an organization other than their personal one, except its last owner.
| Role | Can |
|---|---|
| Owner | Everything, including cancelling the subscription and deleting the organization. |
| Admin | Manage members (except owners and admins), API keys, alerts, endpoints and billing — checkout, plan changes, invoices. Cannot cancel, reactivate or delete the organization. |
| Developer | Read keys, usage, analytics, logs, alerts and endpoints; open support tickets. |
| Viewer | Read-only. |
Accounts and sign-in
- Sign up with an email and a password of 8 to 128 characters that includes upper and lower case letters, a digit and a symbol.
- Sign in with a password, a magic link (emailed, valid for 15 minutes), Google or GitHub. A Google or GitHub sign-in whose email already has an account is linked to that account.
- Password reset links are valid for one hour.
- Two-factor authentication works with any TOTP authenticator app and comes with 10 one-time backup codes. It applies to password sign-in.
- You can delete your account yourself (password required). Deletion is blocked while you are the only owner of an organization that has other members.
Plans and billing
Plans, prices and limits are read from the live plan API (GET https://api.iteradian.com/api/v1/plans), so this table matches what the gateway enforces. The list can grow as plans are added.
| Plan | Price / month | Includes |
|---|---|---|
| Free RPC | $0/mo | WebSocket Subscriptions · Every Network · Community Support |
| Developer RPC | $39/mo | WebSocket Subscriptions · Shared Infrastructure · Automatic Failover · Email Support |
| Professional RPC | $169/mo | WebSocket Subscriptions · Shared + Priority Infrastructure · Priority Failover · Priority Support · Advanced Analytics |
| Dedicated RPC | Custom Contact sales | Dedicated or isolated infrastructure · Automatic failover where provisioned · Priority Support |
Prices and limits read from the control plane on 27 October 2026.
- New accounts start on a 7-day trial of Developer RPC.
- Dedicated RPC cannot be bought online: checkout and self-service plan changes point you to sales, and the limits are set per contract.
- Plan changes are prorated and the difference is invoiced immediately through Stripe. The dashboard shows a preview first.
- Cancelling takes effect at the end of the current period, and the subscription can be reactivated until then. Only owners can cancel or reactivate.
- Payment methods and invoices are managed in the Stripe customer portal, opened from Billing.
- Overage, where a plan has it, is described under Limits, quotas and overage.
Questions and limitations
- Do you support WebSockets?
- Yes. Open wss://rpc.iteradian.com/ws/v1/{network} with the same API key, in an X-Api-Key or Authorization: Bearer header, or as ?apiKey= where a browser cannot set headers. eth_subscribe, Solana *Subscribe and other subscription methods work. Every message you send counts as a request, like an HTTP call (a batch of N counts as N); notifications the node pushes are not charged. An organization can hold max(5, a quarter of its concurrency limit) streams open at once.
- Can I use trace_*, debug_* or archive queries?
- They are forwarded like any other method, but whether they work depends on the node that serves the request. They are not guaranteed, so test them before you depend on them.
- Are test keys limited to testnets?
- No. Live and test are labels for organizing keys. Either kind can call any network the key is allowed to use.
- Is there a daily limit or a burst allowance per key?
- No. The limits are your organization’s per-second rate, concurrency and monthly quota. A key can only have a lower per-second limit of its own.
- Can I choose which node, region or priority my requests use?
- No. Routing is automatic: requests go to a healthy node for the network and fail over when one does not answer. The dashboard’s Endpoints section is for monitoring, not routing.
- Can I invite someone who has no account yet?
- Not yet. They need an Iteradian account first; then an owner or admin adds them by email and they get access immediately. No invitation email is sent.
- Is there a public status page?
- No. The dashboard’s Status view shows the health of your own organization’s networks and endpoints.
- Is there an OpenAPI or Swagger reference?
- Not a public one. Use the route reference in the Management API section, or the SDKs.
- Can I buy a contract-priced plan online?
- No. Plans priced per contract are arranged with sales, and their limits are set in the contract.
- Does two-factor authentication apply to magic-link, Google or GitHub sign-in?
- No. Two-factor authentication applies to password sign-in.
- Can I call the gateway straight from a browser?
- You can, but you should not: a key shipped to a browser or an app can be read by anyone. Send the calls through your own backend.
Articles and guides
Ready to send a request?
Create an account and a key — the 7-day trial starts immediately.
Get an API key