{ "openapi": "3.0.0", "info": { "title": "RouteMesh API", "version": "1.0.0", "description": "HTTP API for routing JSON-RPC requests across providers, managing API keys, and viewing usage.", "license": { "name": "Proprietary", "url": "https://routeme.sh" } }, "servers": [ { "url": "https://api.routeme.sh", "description": "API server \u2014 health, chains, API keys, usage, and public submissions" }, { "url": "https://lb.routeme.sh", "description": "RPC router (primary load balancer)" }, { "url": "https://lb2.routeme.sh", "description": "RPC router (AWS backup load balancer)" } ], "security": [], "tags": [ { "name": "RPC", "description": "Forward JSON-RPC requests to the router." }, { "name": "Chains", "description": "Discover supported chains." }, { "name": "Submissions", "description": "Public chain and node listing requests (rate-limited per IP)." }, { "name": "API Keys", "description": "Manage your API keys for self-service access." }, { "name": "Usage", "description": "View your usage and billing data." }, { "name": "Pricing", "description": "Current RPC route and websocket notification prices (public, rate-limited)." }, { "name": "Health", "description": "Service health checks." }, { "name": "Provider", "description": "Provider-scoped management endpoints for managing node plans, methods, and nodes. Authenticated with a management token whose customer is linked to a provider." } ], "paths": { "/health": { "get": { "operationId": "getHealth", "tags": [ "Health" ], "summary": "Service health", "description": "Public health endpoint used by load balancers and uptime checks.", "responses": { "200": { "description": "Service is healthy and serving requests", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" } }, "required": [ "success", "message" ], "additionalProperties": false }, "example": { "success": true, "message": "The service is ready to serve requests" } } } } } }, "servers": [ { "url": "https://api.routeme.sh" } ] }, "/chains/rpc": { "get": { "operationId": "getChainsRpc", "tags": [ "Chains" ], "summary": "List supported RPC chains", "description": "Returns the EVM chains supported over HTTP RPC, sorted by chain ID. Public endpoint, no authentication required. Returns an empty array when no chains are supported.", "responses": { "200": { "description": "Supported RPC chains", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChainInfo" } }, "example": [ { "chain_id": "1", "name": "Ethereum Mainnet" }, { "chain_id": "8453", "name": "Base" } ] } } }, "500": { "description": "Internal server error" } } }, "servers": [ { "url": "https://api.routeme.sh" } ] }, "/chains/ws": { "get": { "operationId": "getChainsWs", "tags": [ "Chains" ], "summary": "List supported WebSocket chains", "description": "Returns the EVM chains supported over WebSocket, sorted by chain ID. Public endpoint, no authentication required. Returns an empty array when no chains are supported.", "responses": { "200": { "description": "Supported WebSocket chains", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChainInfo" } }, "example": [ { "chain_id": "1", "name": "Ethereum Mainnet" } ] } } }, "500": { "description": "Internal server error" } } }, "servers": [ { "url": "https://api.routeme.sh" } ] }, "/rpc/{chainId}/{apiKey}": { "post": { "operationId": "postRpc", "tags": [ "RPC" ], "summary": "JSON-RPC proxy", "description": "Send a single JSON-RPC request or a JSON-RPC batch (array). Replace {apiKey} with your actual API key.", "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" }, { "name": "apiKey", "in": "path", "required": true, "description": "Your RouteMesh API key (from the dashboard).", "schema": { "type": "string", "format": "password" }, "example": "your-api-key" } ], "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" } }, "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/JsonRpcResponse" }, { "$ref": "#/components/schemas/JsonRpcBatchResponse" } ] } } } }, "400": { "description": "Bad request (e.g. invalid JSON or invalid JSON-RPC payload)" }, "401": { "description": "Unauthorized (invalid API key)" }, "403": { "description": "Forbidden (domain not allowed)" }, "422": { "description": "Unprocessable entity (e.g. chain not supported or method not supported)" }, "424": { "description": "Failed dependency (all upstream providers failed with non-2xx responses)" }, "429": { "description": "Too many requests (all upstream providers rate limited / on cooldown)" }, "500": { "description": "Internal server error" }, "504": { "description": "Gateway timeout (router timed out waiting for upstream providers)" } } }, "servers": [ { "url": "https://lb.routeme.sh", "description": "Primary RPC router" }, { "url": "https://lb2.routeme.sh", "description": "AWS backup RPC router" } ] }, "/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", "tags": [ "API Keys" ], "summary": "List my API keys", "description": "Returns the authenticated customer's API keys. Excludes the secret key value; use X-Hint for identification.", "security": [ { "MgmtKeyAuth": [] } ], "responses": { "200": { "description": "List of API keys", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ApiKeyResponse" } } } } }, "401": { "description": "Unauthorized" } } }, "post": { "operationId": "createApiKey", "tags": [ "API Keys" ], "summary": "Create API key", "description": "Creates a new API key for the authenticated customer. The secret key value is returned once \u2014 store it securely.", "security": [ { "MgmtKeyAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiKeyCreateRequest" } } } }, "responses": { "201": { "description": "API key created (secret returned once)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiKeyCreatedResponse" } } } }, "400": { "description": "Bad request (invalid domains, routing strategy, or missing fields)" }, "401": { "description": "Unauthorized" }, "500": { "description": "Internal server error" } } }, "servers": [ { "url": "https://api.routeme.sh" } ] }, "/usage": { "get": { "operationId": "getUsage", "tags": [ "Usage" ], "summary": "Get usage data", "description": "Returns customer-scoped usage aggregates. Supports filtering by time range, chain, API key, grouping, and granularity. By default returns summary and balance.", "security": [ { "MgmtKeyAuth": [] } ], "parameters": [ { "name": "from", "in": "query", "description": "Start time (RFC3339). Defaults to 30 days ago.", "schema": { "type": "string", "format": "date-time" }, "example": "2025-01-01T00:00:00Z" }, { "name": "to", "in": "query", "description": "End time (RFC3339). Defaults to now.", "schema": { "type": "string", "format": "date-time" }, "example": "2025-07-01T00:00:00Z" }, { "name": "include", "in": "query", "description": "Comma-separated list of sections to include. Options: summary, balance, by_chain, by_api_key, by_api_key_chain, top_methods, time_series, by_scenario. Default: summary,balance.", "schema": { "type": "string", "example": "summary,balance,by_chain,by_api_key" } }, { "name": "group_by", "in": "query", "description": "Group usage by a dimension. Options: chain, api_key, api_key,chain, method, day.", "schema": { "type": "string", "example": "chain" } }, { "name": "granularity", "in": "query", "description": "Time bucket size. Options: day, hour. Default: day.", "schema": { "type": "string", "enum": [ "day", "hour" ] }, "example": "day" }, { "name": "chain_id", "in": "query", "description": "Filter by chain ID (e.g. 1, 137, 8453).", "schema": { "type": "string" }, "example": "1" }, { "name": "api_key_id", "in": "query", "description": "Filter by API key numeric ID (found in list response).", "schema": { "type": "integer" }, "example": 1 }, { "name": "limit", "in": "query", "description": "Maximum number of rows returned (default and max depend on config).", "schema": { "type": "integer", "minimum": 1 }, "example": 100 } ], "responses": { "200": { "description": "Usage data", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageResponse" } } } }, "400": { "description": "Bad request (invalid time range, include value, group_by, or granularity)" }, "401": { "description": "Unauthorized" }, "500": { "description": "Internal server error" }, "503": { "description": "Usage data temporarily unavailable (ClickHouse)" } } }, "servers": [ { "url": "https://api.routeme.sh" } ] }, "/api-keys/{id}": { "servers": [ { "url": "https://api.routeme.sh" } ], "put": { "operationId": "updateApiKey", "tags": [ "API Keys" ], "summary": "Update API key", "description": "Partially updates one of the authenticated customer's API keys by numeric ID. Omitted fields leave the stored value unchanged. Use the id from GET /api-keys.", "security": [ { "MgmtKeyAuth": [] } ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Numeric API key ID (from GET /api-keys). Not the secret rm_ key string.", "schema": { "type": "integer" }, "example": 1 } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiKeyUpdateRequest" } } } }, "responses": { "200": { "description": "API key updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiKeyResponse" } } } }, "400": { "description": "Bad request (invalid domains or non-numeric id)" }, "401": { "description": "Unauthorized" }, "404": { "description": "API key not found" }, "500": { "description": "Internal server error" } } } }, "/chains/requests": { "servers": [ { "url": "https://api.routeme.sh" } ], "post": { "operationId": "submitChainRequest", "tags": [ "Submissions" ], "summary": "Submit chain request", "description": "Public endpoint to request listing a new chain. Rate-limited to 5 submissions per IP per day. Optional X-Api-Key with an admin or agent management token skips the per-IP limit. Submitted RPC URLs are screened; at least one must qualify.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainRequestCreate" } } } }, "responses": { "201": { "description": "Chain request created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmissionCreatedResponse" } } } }, "400": { "description": "Validation or screening failure" }, "401": { "description": "Unauthorized (invalid X-Api-Key when provided)" }, "409": { "description": "Chain already exists or pending request exists for this chain ID" }, "429": { "description": "Per-IP daily submission limit exceeded" }, "500": { "description": "Internal server error" } } } }, "/nodes/requests": { "servers": [ { "url": "https://api.routeme.sh" } ], "post": { "operationId": "submitNodeRequest", "tags": [ "Submissions" ], "summary": "Submit node request", "description": "Public endpoint to request listing a new RPC node. Rate-limited to 3 submissions per IP per day. Optional X-Api-Key with an admin or agent management token skips the per-IP limit. The node URL must be HTTPS and pass mandatory EVM screening.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeRequestCreate" } } } }, "responses": { "201": { "description": "Node request created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmissionCreatedResponse" } } } }, "400": { "description": "Validation or screening failure" }, "401": { "description": "Unauthorized (invalid X-Api-Key when provided)" }, "409": { "description": "Node URL already exists or pending request exists" }, "429": { "description": "Per-IP daily submission limit exceeded" }, "500": { "description": "Internal server error" } } } }, "/pricing/rpc": { "servers": [ { "url": "https://api.routeme.sh" } ], "get": { "operationId": "getRoutePrices", "tags": [ "Pricing" ], "summary": "List RPC route prices", "description": "Public endpoint returning current RPC route prices for each vm, chain ID, method, and routing strategy combination. No authentication required. Rate-limited per IP (default 30 requests per 60 seconds). Empty results return an empty JSON array.", "parameters": [ { "name": "vm", "in": "query", "description": "Filter by virtual machine type (e.g. evm).", "schema": { "type": "string" }, "example": "evm" }, { "name": "chain_id", "in": "query", "description": "Filter by chain ID (e.g. 1, 137, 8453).", "schema": { "type": "string" }, "example": "1" }, { "name": "method", "in": "query", "description": "Filter by JSON-RPC method (e.g. eth_blockNumber).", "schema": { "type": "string" }, "example": "eth_blockNumber" }, { "name": "routing_strategy", "in": "query", "description": "Filter by routing strategy.", "schema": { "type": "string", "enum": [ "economy", "performance" ] }, "example": "economy" } ], "responses": { "200": { "description": "Current route prices", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/RoutePrice" } }, "example": [ { "vm": "evm", "chain_id": "1", "method": "eth_blockNumber", "routing_strategy": "economy", "price_per_million": 3 } ] } } }, "429": { "description": "Rate limit exceeded (per-IP limit; default 30 requests per 60 seconds)" }, "503": { "description": "Pricing data temporarily unavailable" } } } }, "/pricing/ws": { "servers": [ { "url": "https://api.routeme.sh" } ], "get": { "operationId": "getWSPrices", "tags": [ "Pricing" ], "summary": "List websocket notification prices", "description": "Public endpoint returning current websocket notification prices per chain ID and subscription type. No authentication required. Rate-limited per IP (default 30 requests per 60 seconds). Empty results return an empty JSON array.", "parameters": [ { "name": "chain_id", "in": "query", "description": "Filter by chain ID (e.g. 1, 137, 8453).", "schema": { "type": "string" }, "example": "1" }, { "name": "subscription_type", "in": "query", "description": "Filter by websocket subscription type (e.g. newHeads).", "schema": { "type": "string" }, "example": "newHeads" } ], "responses": { "200": { "description": "Current websocket notification prices", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/WSNotificationPrice" } }, "example": [ { "vm": "evm", "chain_id": "1", "subscription_type": "newHeads", "price_per_million": 6 } ] } } }, "429": { "description": "Rate limit exceeded (per-IP limit; default 30 requests per 60 seconds)" }, "503": { "description": "Pricing data temporarily unavailable" } } } }, "/provider/plans": { "get": { "operationId": "listProviderPlans", "tags": [ "Provider" ], "summary": "List my plans", "description": "Returns the authenticated provider's pricing plans, or an empty array when the provider has none. Plan creation and pricing edits remain admin-managed.", "security": [ { "MgmtKeyAuth": [] } ], "responses": { "200": { "description": "List of plans or empty array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ProviderPlan" } } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider not resolved - token's customer is not linked to a provider" }, "500": { "description": "Internal server error" } }, "servers": [ { "url": "https://api.routeme.sh" } ] } }, "/provider/plans/{planId}/methods": { "get": { "operationId": "getProviderPlanMethods", "tags": [ "Provider" ], "summary": "List a plan's RPC methods", "description": "Returns the RPC method rows configured for one of the authenticated provider's plans. Returns an empty array when the plan has no methods. Plans not owned by the caller's provider are reported as 404.", "security": [ { "MgmtKeyAuth": [] } ], "parameters": [ { "name": "planId", "in": "path", "required": true, "schema": { "type": "integer" }, "description": "Numeric plan ID." } ], "responses": { "200": { "description": "List of method rows or empty array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ProviderPlanMethod" } } } } }, "400": { "description": "Invalid plan id" }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider not resolved" }, "404": { "description": "Plan not found (or not owned by the caller's provider)" }, "500": { "description": "Internal server error" } }, "servers": [ { "url": "https://api.routeme.sh" } ] }, "post": { "operationId": "insertProviderPlanMethods", "tags": [ "Provider" ], "summary": "Add methods to a plan", "description": "Appends RPC method rows (1-500) to one of the authenticated provider's plans. The plan must be owned by the caller's provider (otherwise 404).", "security": [ { "MgmtKeyAuth": [] } ], "parameters": [ { "name": "planId", "in": "path", "required": true, "schema": { "type": "integer" }, "description": "Numeric plan ID." } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderPlanMethodsInput" } } } }, "responses": { "201": { "description": "Plan methods inserted. Returns a plain-text success message." }, "400": { "description": "Invalid plan id, request body, or validation failure" }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider not resolved" }, "404": { "description": "Plan not found (or not owned by the caller's provider)" }, "500": { "description": "Internal server error" } }, "servers": [ { "url": "https://api.routeme.sh" } ] } }, "/provider/nodes/{nodeId}/status": { "get": { "operationId": "getProviderNodeStatus", "tags": [ "Provider" ], "summary": "Get a node's sync status", "description": "Returns the synchronization status of one of the authenticated provider's nodes. Nodes not owned by the caller's provider are reported as 404.", "security": [ { "MgmtKeyAuth": [] } ], "parameters": [ { "name": "nodeId", "in": "path", "required": true, "schema": { "type": "integer" }, "description": "Numeric node ID." } ], "responses": { "200": { "description": "Node sync status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderNodeStatus" } } } }, "400": { "description": "Invalid node id" }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider not resolved" }, "404": { "description": "Node not found (or not owned by the caller's provider)" }, "500": { "description": "Internal server error" } }, "servers": [ { "url": "https://api.routeme.sh" } ] } }, "/provider/nodes": { "put": { "operationId": "upsertProviderNode", "tags": [ "Provider" ], "summary": "Create or update an HTTP node", "description": "Creates or updates an HTTP RPC node for one of the authenticated provider's plans. The URL must be a public http(s) endpoint (loopback, private, and link-local hosts are rejected). The node is screened before persistence; the request fails with 400 when a mandatory screening test does not pass. Returns the upserted node set to a healthy status.", "security": [ { "MgmtKeyAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderNodeInput" } } } }, "responses": { "200": { "description": "Node upserted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderUpsertNodeResponse" } } } }, "400": { "description": "Invalid request body, non-public URL, or failed mandatory screening" }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider not resolved" }, "404": { "description": "Plan or node not found (or not owned by the caller's provider)" }, "409": { "description": "Node URL already exists in a different plan" }, "500": { "description": "Internal server error" } }, "servers": [ { "url": "https://api.routeme.sh" } ] } }, "/provider/nodes/ws": { "put": { "operationId": "upsertProviderWSNode", "tags": [ "Provider" ], "summary": "Create or update a WebSocket node", "description": "Creates or updates a WebSocket RPC node for one of the authenticated provider's plans. The URL must be a public wss:// endpoint (loopback, private, and link-local hosts are rejected) that accepts eth_subscribe(\"newHeads\"); the server dials the node to verify before persisting. Returns the upserted node set to a healthy status.", "security": [ { "MgmtKeyAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderWSNodeInput" } } } }, "responses": { "200": { "description": "WebSocket node upserted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderUpsertWSNodeResponse" } } } }, "400": { "description": "Invalid request body, non-public URL, or failed newHeads acceptance screening" }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider not resolved" }, "404": { "description": "Plan not found (or not owned by the caller's provider)" }, "409": { "description": "URL already registered to another plan" }, "500": { "description": "Internal server error" } }, "servers": [ { "url": "https://api.routeme.sh" } ] } }, "/provider/nodes/status": { "post": { "operationId": "setProviderNodeStatus", "tags": [ "Provider" ], "summary": "Enable, disable, or delete a node", "description": "Sets the status of one of the authenticated provider's nodes to enable, disable, or delete (hide). Allowed statuses: healthy, disabled by provider, provider-deleted.", "security": [ { "MgmtKeyAuth": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderSetNodeStatusInput" } } } }, "responses": { "200": { "description": "Node status updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderSetNodeStatusResponse" } } } }, "400": { "description": "Invalid request body, node id, or status" }, "401": { "description": "Unauthorized" }, "403": { "description": "Provider not resolved" }, "404": { "description": "Node not found (or not owned by the caller's provider)" }, "500": { "description": "Internal server error" } }, "servers": [ { "url": "https://api.routeme.sh" } ] } } }, "components": { "securitySchemes": { "MgmtKeyAuth": { "type": "apiKey", "in": "header", "name": "X-Api-Key", "description": "Management token from the RouteMesh dashboard (Settings \u2192 Management Tokens). Required for customer API endpoints (/api-keys, /usage). Tokens are prefixed rmtm_ and scoped to your account. Authenticate by passing the token in the X-Api-Key header. Separate from RPC service keys (rm_), which authenticate dApp traffic to the routing layer." } }, "schemas": { "RoutePrice": { "type": "object", "properties": { "vm": { "type": "string", "description": "Virtual machine type (e.g. \"evm\")." }, "chain_id": { "type": "string", "description": "Numeric chain ID (e.g. \"1\", \"137\", \"8453\")." }, "method": { "type": "string", "description": "JSON-RPC method name (e.g. eth_blockNumber)." }, "routing_strategy": { "type": "string", "enum": [ "economy", "performance" ], "description": "Routing strategy the price applies to." }, "price_per_million": { "type": "number", "description": "Price per one million requests." } }, "required": [ "vm", "chain_id", "method", "routing_strategy", "price_per_million" ], "additionalProperties": false }, "WSNotificationPrice": { "type": "object", "properties": { "vm": { "type": "string", "enum": [ "evm" ], "description": "Virtual machine type (currently always \"evm\")." }, "chain_id": { "type": "string", "description": "Numeric chain ID (e.g. \"1\", \"137\", \"8453\")." }, "subscription_type": { "type": "string", "description": "Websocket subscription type (e.g. \"newHeads\")." }, "price_per_million": { "type": "number", "description": "Price per one million notifications." } }, "required": [ "vm", "chain_id", "subscription_type", "price_per_million" ], "additionalProperties": false }, "ChainInfo": { "type": "object", "properties": { "chain_id": { "type": "string", "description": "Numeric chain ID (e.g. \"1\", \"137\", \"8453\")." }, "name": { "type": "string", "description": "Human-readable chain name." } }, "required": [ "chain_id", "name" ], "additionalProperties": false }, "JsonRpcRequest": { "type": "object", "properties": { "jsonrpc": { "type": "string", "enum": [ "2.0" ] }, "method": { "type": "string", "description": "JSON-RPC method name (e.g. eth_blockNumber, eth_call)." }, "params": { "oneOf": [ { "type": "array", "items": {} }, { "type": "object", "additionalProperties": true } ], "description": "Method parameters (varies by method)." }, "id": {} }, "required": [ "jsonrpc", "method", "id" ], "additionalProperties": false }, "JsonRpcBatchRequest": { "type": "array", "items": { "$ref": "#/components/schemas/JsonRpcRequest" } }, "JsonRpcError": { "description": "JSON-RPC error object. See [RPC Error Codes](/rpc-error-codes) for full code \u2192 meaning and when each occurs.", "type": "object", "properties": { "code": { "type": "integer", "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", "description": "Human-readable error message. eth_getLogs limit errors may include a block-range hint suffix: \"; try a block range of at most N blocks\"." }, "data": { "description": "Optional additional error data." } }, "required": [ "code", "message" ], "additionalProperties": true }, "JsonRpcResponse": { "type": "object", "properties": { "jsonrpc": { "type": "string", "enum": [ "2.0" ] }, "id": {}, "result": { "description": "Result value (varies by JSON-RPC method)." }, "error": { "anyOf": [ { "$ref": "#/components/schemas/JsonRpcError" } ] } }, "required": [ "jsonrpc", "id" ], "additionalProperties": true }, "JsonRpcBatchResponse": { "type": "array", "items": { "$ref": "#/components/schemas/JsonRpcResponse" } }, "ApiKeyCreateRequest": { "type": "object", "properties": { "name": { "type": "string", "description": "Friendly name for this key (e.g. \"Production\", \"Staging\").", "nullable": true }, "allowed_domains": { "type": "array", "items": { "type": "string" }, "description": "List of allowed origins/domains. Requests from other domains are rejected with 403.", "minItems": 1 }, "routing_strategy": { "type": "string", "enum": [ "economy", "performance" ], "description": "economy \u2014 most competitive prices; performance \u2014 fastest routes." } }, "required": [ "allowed_domains", "routing_strategy" ], "additionalProperties": false }, "ApiKeyUpdateRequest": { "type": "object", "properties": { "allowed_domains": { "type": "array", "items": { "type": "string" }, "description": "Replace allowed domains list. Omit to keep current value.", "nullable": true }, "name": { "type": "string", "description": "Update friendly name. Omit to keep current value.", "nullable": true }, "active": { "type": "boolean", "description": "Activate or deactivate the key. Omit to keep current value.", "nullable": true } }, "additionalProperties": false }, "ApiKeyCreatedResponse": { "type": "object", "properties": { "id": { "type": "integer" }, "customer_id": { "type": "integer" }, "allowed_domains": { "type": "array", "items": { "type": "string" } }, "api_key": { "type": "string", "description": "The secret API key. Save this \u2014 it is returned only once." }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "name": { "type": "string", "nullable": true }, "routing_strategy": { "type": "string", "enum": [ "economy", "performance" ] }, "active": { "type": "boolean" }, "bypass_credit_check": { "type": "boolean" } }, "required": [ "id", "customer_id", "allowed_domains", "api_key", "created_at", "updated_at", "name", "routing_strategy", "active", "bypass_credit_check" ], "additionalProperties": false }, "ApiKeyResponse": { "type": "object", "properties": { "id": { "type": "integer", "description": "Internal key ID (for filtering /usage)." }, "name": { "type": "string", "nullable": true, "description": "Friendly name." }, "active": { "type": "boolean", "description": "Whether the key is active." }, "allowed_domains": { "type": "array", "items": { "type": "string" }, "description": "Allowed domains." }, "routing_strategy": { "type": "string", "enum": [ "economy", "performance" ] }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } }, "required": [ "id", "name", "active", "allowed_domains", "routing_strategy", "created_at", "updated_at" ], "additionalProperties": false }, "UsagePeriod": { "type": "object", "properties": { "from": { "type": "string", "format": "date-time" }, "to": { "type": "string", "format": "date-time" } }, "required": [ "from", "to" ] }, "UsageSummary": { "type": "object", "properties": { "credits_consumed": { "type": "number", "description": "Total credits spent in the period." }, "request_count": { "type": "integer", "format": "int64", "description": "Total number of requests." }, "credits_per_request": { "type": "number", "description": "Average cost per request." } }, "required": [ "credits_consumed", "request_count", "credits_per_request" ] }, "UsageBalance": { "type": "object", "properties": { "credits": { "type": "number", "description": "Current credit balance." }, "as_of": { "type": "string", "format": "date-time", "description": "Timestamp of the balance snapshot." } }, "required": [ "credits", "as_of" ] }, "UsageByChain": { "type": "object", "properties": { "chain_id": { "type": "string" }, "credits_consumed": { "type": "number" }, "request_count": { "type": "integer", "format": "int64" } }, "required": [ "chain_id", "credits_consumed", "request_count" ] }, "UsageByAPIKey": { "type": "object", "properties": { "api_key_id": { "type": "integer" }, "name": { "type": "string", "nullable": true }, "key_hint": { "type": "string", "description": "Masked API key (e.g. rm_a\u2026456)." }, "credits_consumed": { "type": "number" }, "request_count": { "type": "integer", "format": "int64" } }, "required": [ "api_key_id", "key_hint", "credits_consumed", "request_count" ] }, "UsageByAPIKeyChain": { "type": "object", "properties": { "api_key_id": { "type": "integer" }, "name": { "type": "string", "nullable": true }, "key_hint": { "type": "string" }, "chain_id": { "type": "string" }, "credits_consumed": { "type": "number" }, "request_count": { "type": "integer", "format": "int64" } }, "required": [ "api_key_id", "key_hint", "chain_id", "credits_consumed", "request_count" ] }, "UsageTopMethod": { "type": "object", "properties": { "method": { "type": "string" }, "credits_consumed": { "type": "number" }, "request_count": { "type": "integer", "format": "int64" } }, "required": [ "method", "credits_consumed", "request_count" ] }, "UsageTimeSeriesPoint": { "type": "object", "properties": { "bucket": { "type": "string", "format": "date-time" }, "credits_consumed": { "type": "number" }, "request_count": { "type": "integer", "format": "int64" } }, "required": [ "bucket", "credits_consumed", "request_count" ] }, "UsageByScenario": { "type": "object", "properties": { "scenario": { "type": "string", "description": "Outcome scenario (e.g. first_hop_success, retry, timeout)." }, "credits_consumed": { "type": "number" }, "request_count": { "type": "integer", "format": "int64" } }, "required": [ "scenario", "credits_consumed", "request_count" ] }, "UsageResponse": { "type": "object", "properties": { "customer_id": { "type": "integer" }, "period": { "$ref": "#/components/schemas/UsagePeriod" }, "summary": { "$ref": "#/components/schemas/UsageSummary", "description": "Aggregate credits and request count." }, "balance": { "$ref": "#/components/schemas/UsageBalance", "description": "Current credit balance." }, "by_chain": { "type": "array", "items": { "$ref": "#/components/schemas/UsageByChain" }, "description": "Per-chain breakdown." }, "by_api_key": { "type": "array", "items": { "$ref": "#/components/schemas/UsageByAPIKey" }, "description": "Per-API-key breakdown." }, "by_api_key_chain": { "type": "array", "items": { "$ref": "#/components/schemas/UsageByAPIKeyChain" }, "description": "Per-API-key, per-chain breakdown." }, "top_methods": { "type": "array", "items": { "$ref": "#/components/schemas/UsageTopMethod" }, "description": "Top RPC methods by spend." }, "time_series": { "type": "array", "items": { "$ref": "#/components/schemas/UsageTimeSeriesPoint" }, "description": "Time-bucketed usage data." }, "by_scenario": { "type": "array", "items": { "$ref": "#/components/schemas/UsageByScenario" }, "description": "Usage by routing outcome scenario." }, "groups": { "type": "array", "items": { "type": "object", "properties": { "api_key_id": { "type": "integer", "nullable": true }, "name": { "type": "string", "nullable": true }, "key_hint": { "type": "string", "nullable": true }, "chain_id": { "type": "string", "nullable": true }, "method": { "type": "string", "nullable": true }, "scenario": { "type": "string", "nullable": true }, "day": { "type": "string", "nullable": true }, "credits_consumed": { "type": "number" }, "request_count": { "type": "integer", "format": "int64" } }, "required": [ "credits_consumed", "request_count" ] }, "description": "Grouped results when group_by is specified." } }, "required": [ "customer_id", "period" ], "additionalProperties": false }, "ChainRequestCreate": { "type": "object", "properties": { "name": { "type": "string" }, "chain_id": { "type": "string", "description": "Decimal or 0x-prefixed chain ID (e.g. \"137\")." }, "short_name": { "type": "string" }, "native_currency_name": { "type": "string" }, "native_currency_decimals": { "type": "integer", "minimum": 0, "default": 0 }, "info_url": { "type": "string", "format": "uri" }, "icon_url": { "type": "string", "format": "uri", "nullable": true }, "rpc_urls": { "type": "array", "items": { "type": "string", "format": "uri" }, "minItems": 1, "maxItems": 5, "description": "HTTPS RPC URLs to screen (max 5). At least one must pass screening." }, "explorer_urls": { "type": "array", "items": { "type": "string", "format": "uri" } }, "requestor_email": { "type": "string", "format": "email" }, "requestor_name": { "type": "string" } }, "required": [ "name", "chain_id", "short_name", "native_currency_name", "info_url", "rpc_urls", "requestor_email", "requestor_name" ], "additionalProperties": false }, "NodeRequestCreate": { "type": "object", "properties": { "name": { "type": "string" }, "url": { "type": "string", "format": "uri", "description": "HTTPS RPC endpoint URL." }, "vm": { "type": "string", "enum": [ "evm" ], "description": "Virtual machine type (currently only evm)." }, "email": { "type": "string", "format": "email" }, "privacy_policy_url": { "type": "string", "format": "uri", "nullable": true }, "notes": { "type": "string", "nullable": true } }, "required": [ "name", "url", "vm", "email" ], "additionalProperties": false }, "SubmissionCreatedResponse": { "type": "object", "properties": { "id": { "type": "integer", "description": "Created request ID." } }, "required": [ "id" ], "additionalProperties": false }, "ProviderPlan": { "type": "object", "properties": { "id": { "type": "integer", "description": "Plan ID." }, "created_at": { "type": "string", "format": "date-time" }, "provider": { "type": "string", "description": "Provider identifier." }, "provider_id": { "type": "integer" }, "name": { "type": "string" }, "price": { "type": "number" }, "quota": { "type": "number" }, "quota_unit": { "type": "string" }, "description": { "type": "string" }, "overage_price": { "type": "number" }, "overage_limit": { "type": "number" }, "rate_limit_req": { "type": "number" }, "rate_limit_req_interval_sec": { "type": "number" }, "rate_limit_cr": { "type": "number" }, "rate_limit_cr_interval_sec": { "type": "number" }, "billing_fixed_day": { "type": "integer", "nullable": true }, "billing_interval_days": { "type": "integer", "nullable": true }, "billing_anchored_start_date": { "type": "string", "format": "date-time", "nullable": true } } }, "ProviderPlanMethod": { "type": "object", "properties": { "method": { "type": "string", "description": "RPC method name, e.g. eth_blockNumber." }, "vm": { "type": "string", "description": "Virtual machine type, e.g. evm." }, "node_target_type": { "type": "string", "description": "Node target type the method routes to." }, "cost": { "type": "integer", "description": "Credit cost per call (0 = free)." }, "rate_limit": { "type": "integer", "nullable": true, "description": "Optional per-call rate limit." }, "rate_limit_interval_sec": { "type": "integer", "nullable": true, "description": "Rate limit window in seconds." }, "chain_id": { "type": "string", "nullable": true, "description": "Chain this cost applies to; null/omitted for all chains." } } }, "ProviderPlanMethodsInput": { "type": "object", "properties": { "methods": { "type": "array", "minItems": 1, "maxItems": 500, "items": { "$ref": "#/components/schemas/ProviderPlanMethodInput" } } }, "required": [ "methods" ] }, "ProviderPlanMethodInput": { "type": "object", "properties": { "method": { "type": "string" }, "vm": { "type": "string" }, "node_target_type": { "type": "string" }, "cost": { "type": "integer", "minimum": 0 }, "rate_limit": { "type": "integer", "minimum": 0 }, "rate_limit_interval_sec": { "type": "integer", "minimum": 0 }, "chain_id": { "type": "string", "nullable": true } }, "required": [ "method", "vm", "node_target_type", "cost" ] }, "ProviderNodeStatus": { "type": "object", "properties": { "node_id": { "type": "integer" }, "in_sync": { "type": "boolean" }, "status": { "type": "string", "description": "ok or out_of_sync" } } }, "ProviderNodeInput": { "type": "object", "properties": { "plan_id": { "type": "integer", "description": "Plan ID the node belongs to (must be owned by the provider)." }, "url": { "type": "string", "description": "Public http(s) endpoint URL of the node." }, "vm": { "type": "string", "description": "Virtual machine type, e.g. evm." }, "rate_limit": { "type": "number", "description": "Requests per interval (0 = unlimited)." }, "rate_limit_interval_sec": { "type": "integer", "description": "Rate limit window in seconds." }, "source": { "type": "string", "enum": [ "provider", "website", "erpc", "node_request", "new_chain_request" ], "description": "Node source (default provider)." } }, "required": [ "plan_id", "url", "vm", "rate_limit", "rate_limit_interval_sec" ] }, "ProviderUpsertNodeResponse": { "type": "object", "properties": { "message": { "type": "string" }, "node": { "type": "object" }, "status": { "type": "string", "description": "healthy on success." } } }, "ProviderWSNodeInput": { "type": "object", "properties": { "plan_id": { "type": "integer", "description": "Plan ID the WebSocket node belongs to (must be owned by the provider)." }, "chain_id": { "type": "string", "description": "Chain ID the node serves, e.g. 137." }, "url": { "type": "string", "description": "Public wss:// endpoint URL; must accept eth_subscribe(\"newHeads\")." } }, "required": [ "plan_id", "chain_id", "url" ] }, "ProviderUpsertWSNodeResponse": { "type": "object", "properties": { "message": { "type": "string" }, "node_ws": { "type": "object" }, "status": { "type": "string", "description": "healthy on success." } } }, "ProviderSetNodeStatusInput": { "type": "object", "properties": { "node_id": { "type": "integer" }, "status": { "type": "string", "description": "healthy (enable), disabled by provider (disable), or provider-deleted (delete)." } }, "required": [ "node_id", "status" ] }, "ProviderSetNodeStatusResponse": { "type": "object", "properties": { "node_id": { "type": "integer" }, "status": { "type": "string" } } } }, "headers": { "XBatchId": { "description": "Correlation ID for this HTTP request. Save it and share with RouteMesh support to help trace requests across logs and analytics.", "schema": { "type": "string" }, "example": "1f4f3b23-1c2b-4c87-9c2f-7e2e0f0df4b5" } } } }