Skip to main content

RPC

One read-only JSON-RPC URL for Bittensor — health-aware load balancing, failover, and abuse controls. Plus the pool roster, endpoint catalog, and proxy usage analytics. No API key.

Last updated

Proxy

POST a single JSON-RPC object to /rpc/v1/{network}. Supported networks: finney (mainnet) and test (testnet). WebSocket upgrade is not available on this HTTP path — use wss.metagraph.sh or a public WSS endpoint.

POST https://api.metagraph.sh/rpc/v1/{network}
  • finneyhttps://api.metagraph.sh/rpc/v1/finney
  • testhttps://api.metagraph.sh/rpc/v1/test
curl -s 'https://api.metagraph.sh/rpc/v1/finney' \
  -X POST -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"chain_getHeader","params":[]}'

Catalog & analytics

Static registry projections and live proxy telemetry. Live explorer UI for pools and traffic lives on Endpoints.

MethodPathSummaryNotes
POST/rpc/v1/{network}Read-only JSON-RPC reverse proxyNetwork segment is finney (mainnet) or test (testnet). Single JSON-RPC object only — no batches, no HTTP WebSocket upgrade.
GET/api/v1/rpc/poolsProxy pool roster + live eligibilityServes rpc/pools.json with probe-derived health overlaid from KV so dead upstreams show as ineligible.
GET/api/v1/rpc/endpointsBase-layer Subtensor RPC/WSS registryFilterable catalog (kind, layer, status, provider, pool_eligible, latency). Pair with the live table on Endpoints.
GET/api/v1/rpc/usageProxy usage analyticsRequest volume, latency p50/p95, failover/error/cache rates, per-endpoint and per-network distribution. ?window=7d|30d.

Allowlisted methods

Only safe read methods pass. Mutating and heavy prefixes are denied. State-query methods need param validation and a separate rate budget.

Denied prefixes get rejected outright

author_, state_call, sudo_, payment_, and contracts_ calls never reach the upstream node — the proxy rejects them before dispatch, not after.

Safe methods

chain_getBlock · chain_getBlockHash · chain_getFinalizedHead · chain_getHeader · rpc_methods · state_getRuntimeVersion · system_chain · system_health · system_name · system_properties · system_version

State-query (extra rate budget)

state_getStorage · state_getKeysPaged

Denied prefixes

author_* · state_call* · sudo_* · payment_* · contracts_*

Gated fullnode access

An account-gated tier for real fullnode RPC access — not just the read-only proxy above. Requires a wallet-signed login; no invite code, self-serve. Grants the same safe read methods as the public proxy, plus author_submitExtrinsic (real transaction broadcast), at a materially higher rate limit than the keyless tier. Every key starts on the default (free) tier; a higher tier is granted directly to your account, not by a code you present.

1. Request a challenge

curl -s https://api.metagraph.sh/api/v1/auth/wallet/challenge \
  -X POST -H 'content-type: application/json' \
  -d '{"ss58":"YOUR_SS58_ADDRESS"}'

Returns a message to sign and how long it stays valid.

2. Sign the message with your wallet

Sign the returned message as raw bytes with your own wallet signer (e.g. @polkadot/extension-dapp's signRaw({ address, data: message, type: "bytes" })). The signing key material never reaches this API — only the resulting signature does.

3. Verify and get a session

curl -s https://api.metagraph.sh/api/v1/auth/wallet/verify \
  -X POST -H 'content-type: application/json' \
  -d '{"ss58":"YOUR_SS58_ADDRESS","signature":"YOUR_HEX_SIGNATURE"}'

Returns a session_token — scoped only to key management (create/list/revoke your own keys), not itself the RPC credential.

4. Mint your key

curl -s https://api.metagraph.sh/api/v1/keys \
  -X POST \
  -H "authorization: Bearer YOUR_SESSION_TOKEN"

Returns the full mg_... key exactly once — store it yourself; it's never shown again, along with a key_id. Revoke anytime with DELETE /api/v1/keys/{key_id}, presenting the same session.

5. Call the gated proxy

curl -s 'https://api.metagraph.sh/rpc/v1/fullnode?authorization=YOUR_KEY' \
  -X POST -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"chain_getHeader","params":[]}'

The key travels as an ?authorization= query parameter, not a header — matching the convention several hosted-RPC providers already use, so existing WSS-shaped client code needs minimal changes to point here.

WhatValueNotes
EndpointPOST /rpc/v1/fullnodeIsolated from the public /rpc/v1/{network} pool — no shared failover state.
Method scopeSafe read methods + author_submitExtrinsicEvery other author_/sudo_/payment_/contracts_/state_call call is denied.
Key delivery?authorization= query parameterNot an Authorization header.

Limits

Hard caps on every proxied POST. Matching constants live in workers/config.mjs and workers/request-handlers/rpc-proxy.mjs.

LimitValueNotes
Rate limit100 / 60sPer-client IP on POST /rpc/v1/* (429 + retry-after). Shared binding policy with GraphQL.
State-query rate20 / 60sAdditional budget for state_getStorage / state_getKeysPaged — does not starve ordinary chain/system reads.
Max POST body64 KiBHTTP request body size cap for the read-only proxy.
Max state-query response256 KiBDecoded upstream body cap for state-query methods after fetch.
state_getKeysPaged page250Caller-supplied count is clamped server-side (not rejected).
Failover attempts3Per request across the health-ordered pool before surfacing upstream failure.