From 8c4131b76d78069c890201435d4800c9416fd8c6 Mon Sep 17 00:00:00 2001 From: "maia-cloud-agent[bot]" Date: Fri, 28 Aug 2026 20:08:32 +0000 Subject: [PATCH 1/3] docs-sync v3.0.1: WS page, error codes, public /rpc/evm route, x-batch-ids fix --- api-reference/openapi.json | 63 +++++++++++++++++++++++++++++++++++++- docs.json | 1 + intro/debugging.mdx | 2 +- intro/quick-start.mdx | 14 ++++++++- intro/rpc-error-codes.mdx | 12 +++++++- intro/websockets.mdx | 62 +++++++++++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 intro/websockets.mdx diff --git a/api-reference/openapi.json b/api-reference/openapi.json index 878af20..394378b 100644 --- a/api-reference/openapi.json +++ b/api-reference/openapi.json @@ -289,6 +289,67 @@ } ] }, + "/rpc/evm/{chainId}": { + "post": { + "operationId": "postPublicRpc", + "tags": [ + "RPC" + ], + "summary": "Public JSON-RPC proxy (no API key)", + "description": "Send a single JSON-RPC request or a JSON-RPC batch (array) to the public, anonymous free tier. No API key required. Rate-limited per IP. For higher volume, use an API key at /rpc/{chainId}/{apiKey}.", + "parameters": [ + { + "name": "chainId", + "in": "path", + "required": true, + "description": "Chain ID (e.g. 1 for Ethereum, 137 for Polygon, 8453 for Base).", + "schema": { + "type": "string" + }, + "example": "1" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/JsonRpcRequest" + }, + { + "$ref": "#/components/schemas/JsonRpcBatchRequest" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "JSON-RPC response (single or batch)", + "headers": { + "X-Batch-Id": { + "$ref": "#/components/headers/XBatchId" + } + } + }, + "400": { + "description": "Bad request (e.g. invalid JSON or invalid JSON-RPC payload)" + }, + "429": { + "description": "Too many requests (public per-IP rate limit exceeded)" + }, + "503": { + "description": "Service temporarily unavailable (public free-tier capacity exhausted or unrelated)" + }, + "500": { + "description": "Internal server error" + } + } + } + }, "/api-keys": { "get": { "operationId": "listMyApiKeys", @@ -961,7 +1022,7 @@ "properties": { "code": { "type": "integer", - "description": "Router error codes: -32700 (parse error), -32600 (invalid request), -32602 (invalid params or eth_getLogs block span too large), -32603 (internal error), -32000 (server error), -32001 (chain not supported), -32002 (method not supported), -32003 (all nodes on cooldown), -32005 (eth_getLogs query limit exceeded)." + "description": "Router error codes: -32700 (parse error), -32600 (invalid request), -32601 (insufficient credits), -32602 (invalid params), -32603 (internal error), -32000 (server error), -32001 (chain not supported), -32002 (method not supported), -32003 (all nodes on cooldown), -32005 (eth_getLogs query limit exceeded), -32007 (no block-param capable nodes), -32008 (no providers available), -32009 (all nodes failed), -32011 (no opcode-capable nodes), -32012 (insufficient historical state depth), -32013 (no single provider satisfies all constraints), -32029 (public per-IP rate limit exceeded), -32030 (public free-tier capacity exhausted). See the RPC error codes guide for details." }, "message": { "type": "string", diff --git a/docs.json b/docs.json index 0e2fe8a..f34fd4c 100644 --- a/docs.json +++ b/docs.json @@ -35,6 +35,7 @@ "group": "Integration", "pages": [ "intro/request-behavior", + "intro/websockets", "intro/debugging", "intro/mcp-server", "intro/network-support", diff --git a/intro/debugging.mdx b/intro/debugging.mdx index 1234a55..d1fed8e 100644 --- a/intro/debugging.mdx +++ b/intro/debugging.mdx @@ -18,7 +18,7 @@ Every RPC request returns an `X-Batch-Id` response header (UUID). Save it in you `X-Batch-Id` is per HTTP request: - Single JSON-RPC request: one `X-Batch-Id` -- JSON-RPC batch (array): one `X-Batch-Id` for the whole batch +- JSON-RPC batch (array): one `X-Batch-Ids` header containing the comma-separated batch IDs for each item in the batch ### How to capture it diff --git a/intro/quick-start.mdx b/intro/quick-start.mdx index fc91417..6cfcd02 100644 --- a/intro/quick-start.mdx +++ b/intro/quick-start.mdx @@ -36,7 +36,19 @@ curl -X POST https://lb.routeme.sh/rpc/{chain_id}/{api_key} \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' ``` -For **allowed domains**, **cooldowns**, and **batch requests**, see [Request behavior](/intro/request-behavior). For **error handling**, see [RPC error codes](/intro/rpc-error-codes). +For **allowed domains**, **cooldowns**, and **batch requests**, see [Request behavior](/intro/request-behavior). For **error handling**, see [RPC error codes](/intro/rpc-error-codes). For **real-time event streams**, see [WebSocket API](/intro/websockets). + +## **Public RPC (no API key)** + +You can call RouteMesh without an API key for a limited free tier using the public path `POST /rpc/evm/{chain_id}`. This is intended for light, anonymous access: + +```bash +curl -X POST https://lb.routeme.sh/rpc/evm/1 \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' +``` + +The public route is rate-limited per IP. If you hit the limit or it is temporarily unavailable, the response points you to sign up for a free account for full access. For higher volume, use an API key as shown in [Make your first request](#3-make-your-first-request). ## **Supported networks** diff --git a/intro/rpc-error-codes.mdx b/intro/rpc-error-codes.mdx index 1421d14..2eece06 100644 --- a/intro/rpc-error-codes.mdx +++ b/intro/rpc-error-codes.mdx @@ -12,17 +12,27 @@ For a successful HTTP 200, the response may still contain a JSON-RPC `error` (e. | :----- | :------------------- | :---------------------------------------------------------------------- | | -32700 | Parse error | Request body is not valid JSON. | | -32600 | Invalid request | Malformed JSON-RPC (e.g. missing required fields) or an empty batch. | -| -32602 | Invalid params | Invalid `chainId` in the request path, or an `eth_getLogs` block span that exceeds the router limit. | +| -32601 | Insufficient credits | The API key's credit balance is too low to serve the request (HTTP 402). Top up in the dashboard and retry. | +| -32602 | Invalid params | Invalid `chainId` in the request path, an `eth_getLogs` block span that exceeds the router limit, or a response that is too large. | | -32603 | Internal error | Router encountered an internal failure. Contact support if persistent. | | -32000 | Server error | Unspecified server error (fallback when no specific code applies). | | -32001 | Chain not supported | The given `chainId` has no available nodes or paid plan support. | | -32002 | Method not supported | The JSON-RPC method is not enabled for this chain. | | -32003 | All nodes on cooldown| Every node that could serve the route is temporarily in cooldown (e.g. after rate limits or errors). Retry after a short delay. | | -32005 | Limit exceeded | An `eth_getLogs` query matched too many logs or produced a response that is too large for the requested block span. See [eth_getLogs limits](/intro/request-behavior#eth_getlogs-limits). | +| -32007 | No block-param nodes | No provider supports the custom block number parameter used in the request (e.g. an `eth_getLogs` query with a specific block range). | +| -32008 | No providers available| No providers are currently available to serve the route. | +| -32009 | All nodes failed | Every provider failed with a non-rate-limit error (HTTP 424). Retry once; if it persists, contact support. | +| -32011 | No opcode-capable nodes| No provider supports the requested opcode at the given block (e.g. an `eth_call` at a historical block). | +| -32012 | Insufficient historical depth| No provider has sufficient historical state depth (or `eth_getLogs` earliest-block support) for the requested block. | +| -32013 | No single provider satisfies all constraints| No single provider supports the full combination of requested constraints (e.g. block range, depth, method). Try reducing the block range or using a more recent block. | +| -32029 | Public rate limited | The public (no-API-key) route's per-IP rate limit was exceeded (HTTP 429). Sign up for a free account for full access. | +| -32030 | Public capacity exhausted| The public (no-API-key) route's free-tier capacity is temporarily exhausted. Sign up for a free account for full access. | ## Standard JSON-RPC codes - **-32700** and **-32600** follow the [JSON-RPC 2.0 spec](https://www.jsonrpc.org/specification#error_object) for parse and invalid request errors. +- **-32601** follows the JSON-RPC 2.0 spec for method/params errors and is used here for an empty credit balance. - **-32602** is used for invalid `chainId` (invalid params) and for `eth_getLogs` block-span rejections. - **-32603** is used for internal router errors. - **-32005** follows [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474#error-codes) (limit exceeded) for `eth_getLogs` query-density failures. diff --git a/intro/websockets.mdx b/intro/websockets.mdx new file mode 100644 index 0000000..2c3b1cf --- /dev/null +++ b/intro/websockets.mdx @@ -0,0 +1,62 @@ +--- +title: "WebSocket API" +--- + +RouteMesh supports real-time event streams over WebSocket using the standard Ethereum `eth_subscribe` / `eth_unsubscribe` protocol. This lets you receive pushed notifications — like new blocks or contract logs — without polling. + +## Connecting + +Connect to the WebSocket URL with your API key in the path (same keys you use for HTTP RPC): + +```text +wss://lb.routeme.sh/rpc/{chain_id}/{api_key} +``` + +The connection must be upgraded from HTTP. On a successful handshake, the server returns an `X-WebSocket-Session-ID` header you can use for debugging. + +The handshake validates your API key, origin, and credit balance before the socket is upgraded. Common handshake failures return an HTTP status before upgrade: + +- **402** — Insufficient credits +- **429** — Service draining or too many concurrent connections from your IP (a `Retry-After` header tells you when to retry) +- **503** — All connection slots are currently in use +- **401** — Unauthorized (invalid or inactive API key) + +## Subscribing and receiving notifications + +To subscribe, send `eth_subscribe` with a subscription type: + +```json +{"jsonrpc":"2.0","method":"eth_subscribe","params":["newHeads"],"id":1} +``` + +The server replies with a subscription ID, then streams notifications to you as JSON-RPC `eth_subscription` messages: + +```json +{ + "jsonrpc": "2.0", + "method": "eth_subscription", + "params": { + "subscription": "0x0f5f...", + "result": { ... } + } +} +``` + +To stop receiving events for a subscription, send `eth_unsubscribe` with the subscription ID. + +## Supported subscription types and pricing + +The available subscription types (and their prices) can change as we add chains and providers, so instead of a static list use the live endpoints: + +- `GET /pricing/ws` — current WebSocket notification prices per chain and subscription type (price per million notifications) +- `GET /chains/ws` — the chains currently supported over WebSocket + +## Reliability + +RouteMesh runs WebSocket streams with the same redundancy we apply to HTTP RPC. You get: + +- **Seamless provider failover** — if the node behind your subscription goes down, RouteMesh transparently reconnects to an alternate provider and keeps your subscription alive. No action needed on your side. +- **Gap backfill and deduplication** — on reconnection we replay any missed notifications, drop duplicate events, and keep the stream in order, so you don't lose data. +- **Resumable streams** — you can reconnect your own client and pick up where you left off. For `newHeads` and `logs` subscriptions, gaps are reconstructed automatically. + +This means you can rely on WebSocket as a durable event source rather than treating it as best-effort push. From 4cb26797511668403378f2b3c654efed22b2d387 Mon Sep 17 00:00:00 2001 From: "maia-cloud-agent[bot]" Date: Fri, 28 Aug 2026 20:11:57 +0000 Subject: [PATCH 2/3] =?UTF-8?q?ws=20docs:=20correct=20resumable-streams=20?= =?UTF-8?q?claim=20=E2=80=94=20recovery=20covers=20upstream=20failover,=20?= =?UTF-8?q?not=20client=20reconnect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- intro/websockets.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/intro/websockets.mdx b/intro/websockets.mdx index 2c3b1cf..02b3b03 100644 --- a/intro/websockets.mdx +++ b/intro/websockets.mdx @@ -53,10 +53,10 @@ The available subscription types (and their prices) can change as we add chains ## Reliability -RouteMesh runs WebSocket streams with the same redundancy we apply to HTTP RPC. You get: +RouteMesh runs WebSocket streams with the same redundancy we apply to HTTP RPC: -- **Seamless provider failover** — if the node behind your subscription goes down, RouteMesh transparently reconnects to an alternate provider and keeps your subscription alive. No action needed on your side. -- **Gap backfill and deduplication** — on reconnection we replay any missed notifications, drop duplicate events, and keep the stream in order, so you don't lose data. -- **Resumable streams** — you can reconnect your own client and pick up where you left off. For `newHeads` and `logs` subscriptions, gaps are reconstructed automatically. +- **Seamless provider failover** — if the upstream node behind your subscription goes down, RouteMesh transparently reconnects to an alternate provider while keeping your connection alive. You don't need to re-subscribe. +- **Gap backfill and deduplication** — when we fail over to an alternate provider, we replay any notifications missed during the switch, drop duplicate events, and keep the stream in order, so you don't lose data while connected. + +Because this recovery happens while your connection stays open, you get a durable event stream for the lifetime of the socket. If your client disconnects, subscriptions end with the connection — reconnect and re-subscribe to continue. -This means you can rely on WebSocket as a durable event source rather than treating it as best-effort push. From 0aa66661ab9e0a5b52e8488e90554b99e8eda4d8 Mon Sep 17 00:00:00 2001 From: "maia-cloud-agent[bot]" Date: Fri, 28 Aug 2026 20:16:05 +0000 Subject: [PATCH 3/3] rpc-error-codes: -32601 is JSON-RPC 'Method not found', repurposed for credits (kody review) --- intro/rpc-error-codes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intro/rpc-error-codes.mdx b/intro/rpc-error-codes.mdx index 2eece06..557e4ba 100644 --- a/intro/rpc-error-codes.mdx +++ b/intro/rpc-error-codes.mdx @@ -32,7 +32,7 @@ For a successful HTTP 200, the response may still contain a JSON-RPC `error` (e. ## Standard JSON-RPC codes - **-32700** and **-32600** follow the [JSON-RPC 2.0 spec](https://www.jsonrpc.org/specification#error_object) for parse and invalid request errors. -- **-32601** follows the JSON-RPC 2.0 spec for method/params errors and is used here for an empty credit balance. +- **-32601** is the JSON-RPC 2.0 "Method not found" code, repurposed here to signal an empty credit balance. - **-32602** is used for invalid `chainId` (invalid params) and for `eth_getLogs` block-span rejections. - **-32603** is used for internal router errors. - **-32005** follows [EIP-1474](https://eips.ethereum.org/EIPS/eip-1474#error-codes) (limit exceeded) for `eth_getLogs` query-density failures.