Appearance
Cosmos Hub
Cosmos Hub is served through three different protocols on three different transports — each a distinct API, not three views of one. Pick by what you need:
| HTTPS | https://rpc.au.ro/cosmos — LCD / REST (Cosmos SDK gRPC-gateway) |
| WebSocket | wss://rpc.au.ro/ws/cosmos?apikey=<YOUR_API_KEY> — CometBFT RPC |
| gRPC | rpc.au.ro:8443 (full) / :443 (unary) — Cosmos SDK gRPC |
| Network | cosmoshub-4 (CometBFT 0.38.x) |
| Batch | — (LCD is REST; there is no JSON-RPC envelope to batch) |
| CU | 1 CU per call |
The HTTPS endpoint is REST, not CometBFT JSON-RPC
https://…/cosmos is the LCD REST API (:1317 upstream). It does not speak CometBFT JSON-RPC: a JSON-RPC POST is answered by the gRPC-gateway with {"code":12,"message":"Not Implemented"}, and CometBFT paths like /cosmos/status return HTTP 501.
The CometBFT surface (status, abci_query, subscribe, block, validators, broadcast_tx_*) is reachable over WebSocket only — see CometBFT RPC over WebSocket.
LCD / REST over HTTPS
Standard Cosmos SDK REST. Append the LCD path after the /cosmos segment; the key rides the apikey header.
bash
# node info — network, CometBFT version
curl https://rpc.au.ro/cosmos/cosmos/base/tendermint/v1beta1/node_info \
-H "apikey: $YOUR_API_KEY"
# latest block
curl https://rpc.au.ro/cosmos/cosmos/base/tendermint/v1beta1/blocks/latest \
-H "apikey: $YOUR_API_KEY"
# total supply of uatom
curl "https://rpc.au.ro/cosmos/cosmos/bank/v1beta1/supply/by_denom?denom=uatom" \
-H "apikey: $YOUR_API_KEY"js
const base = 'https://rpc.au.ro/cosmos'
const headers = { apikey: process.env.YOUR_API_KEY }
const info = await fetch(`${base}/cosmos/base/tendermint/v1beta1/node_info`, { headers })
console.log((await info.json()).default_node_info.network) // cosmoshub-4
const bal = await fetch(`${base}/cosmos/bank/v1beta1/balances/cosmos1...`, { headers })
console.log((await bal.json()).balances)python
import os, requests
base = "https://rpc.au.ro/cosmos"
h = {"apikey": os.environ["YOUR_API_KEY"]}
r = requests.get(f"{base}/cosmos/base/tendermint/v1beta1/blocks/latest", headers=h)
print(r.json()["block"]["header"]["height"])
r = requests.get(f"{base}/cosmos/bank/v1beta1/supply/by_denom",
params={"denom": "uatom"}, headers=h)
print(r.json()["amount"])go
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
url := "https://rpc.au.ro/cosmos/cosmos/base/tendermint/v1beta1/syncing"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("apikey", os.Getenv("YOUR_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
b, _ := io.ReadAll(res.Body)
fmt.Println(string(b)) // {"syncing":false}
}Live-verified LCD paths (all GET, all HTTP 200):
Path (after /cosmos) | Returns |
|---|---|
/cosmos/base/tendermint/v1beta1/node_info | network id, CometBFT version, moniker |
/cosmos/base/tendermint/v1beta1/syncing | {"syncing":false} |
/cosmos/base/tendermint/v1beta1/blocks/latest | latest block (header + txs) |
/cosmos/bank/v1beta1/supply/by_denom?denom=uatom | total supply |
/cosmos/bank/v1beta1/balances/{address} | all balances for an account |
/cosmos/staking/v1beta1/validators?pagination.limit=N | validator set (paginated) |
The full surface is the standard Cosmos SDK LCD — every module the node enables (auth, bank, staking, gov, distribution, mint, slashing, ibc, …). A path the node doesn't implement returns HTTP 501{"code":12,"message":"Not Implemented"}.
CometBFT RPC over WebSocket
Everything the LCD can't do — consensus state, abci_query, event subscriptions, tx broadcast — lives on the CometBFT RPC, served over WebSocket. Frames are plain CometBFT JSON-RPC:
bash
npx wscat -H "apikey: $YOUR_API_KEY" -c wss://rpc.au.ro/ws/cosmos
> {"jsonrpc":"2.0","id":1,"method":"status","params":{}}
< {"jsonrpc":"2.0","id":1,"result":{"node_info":{"network":"cosmoshub-4",…},
"sync_info":{"latest_block_height":"32042563",…}}}In a browser the key must ride the query string (WebSocket() can't set headers): wss://rpc.au.ro/ws/cosmos?apikey=<YOUR_API_KEY>.
Live-verified over this transport: status, abci_query, subscribe. block, validators, health, net_info and broadcast_tx_sync are the same CometBFT surface.
Subscriptions
bash
> {"jsonrpc":"2.0","id":1,"method":"subscribe","params":{"query":"tm.event='NewBlock'"}}
< {"jsonrpc":"2.0","id":1,"result":{}}
< {"jsonrpc":"2.0","id":1,"result":{"query":"tm.event='NewBlock'","data":{…}}}tm.event='Tx' streams transactions; attribute matches narrow it further (tm.event='Tx' AND transfer.recipient='cosmos1...'). Reconnect guidance: WebSockets.
Module state via abci_query
bash
> {"jsonrpc":"2.0","id":1,"method":"abci_query",
"params":{"path":"/cosmos.bank.v1beta1.Query/TotalSupply","data":""}}The value is base64 protobuf — decode with cosmjs-types or the module's generated stubs. If you'd rather not hand-decode protobuf, use the LCD (JSON) or gRPC (typed) instead.
CosmJS: use LCD or gRPC, not the Tendermint client
@cosmjs/tendermint-rpc's Tendermint37Client cannot reach this deployment on either transport:
- over HTTPS — it hits the LCD and throws
Got unexpected jsonrpc version: {"code":12,"message":"Not Implemented"}. - over WSS —
WebsocketClientappends its own/websocketsuffix to whatever URL you pass, producingwss://…/ws/cosmos?apikey=<KEY>/websocket, which corrupts the key and fails the handshake.
For CosmJS-style typed module queries use gRPC with cosmjs-types
@grpc/grpc-js. For plain reads use the LCD with any HTTP client. Raw CometBFT calls work over WSS with any WebSocket library that sends the URL verbatim (ws,websocat,wscat).
gRPC
The node's Cosmos SDK gRPC (:9090 upstream), routed by proto package (cosmos.*, ibc.*, cometbft.*, tendermint.*), key as apikeymetadata. :8443 serves every call shape including reflection; :443 handles unary + server-streaming with explicit descriptors (a ready-made cosmos.protoset is published):
bash
# reflection — auth, bank, staking, gov, tx, … (20 services)
grpcurl -H "apikey: $YOUR_API_KEY" rpc.au.ro:8443 list
grpcurl -H "apikey: $YOUR_API_KEY" \
-d '{"address":"cosmos1..."}' \
rpc.au.ro:8443 cosmos.bank.v1beta1.Query/AllBalances
# or on :443 with the published descriptor set
grpcurl -protoset cosmos.protoset -H "apikey: $YOUR_API_KEY" \
-d '{"denom":"uatom"}' \
rpc.au.ro:443 cosmos.bank.v1beta1.Query/SupplyOf
# → {"amount":{"denom":"uatom","amount":"519540980277704"}}Port semantics and descriptor details: gRPC.
Choosing a transport
| You want | Use |
|---|---|
| Balances, validators, gov proposals — as JSON | LCD over HTTPS |
| Typed module queries from an SDK | gRPC (cosmjs-types, cosmpy, grpc-go) |
Live blocks/txs, consensus state, abci_query | CometBFT over WSS |
| Broadcast a signed tx | gRPC cosmos.tx.v1beta1.Service/BroadcastTx, or CometBFT broadcast_tx_sync over WSS |
Limitations
- No CometBFT JSON-RPC over HTTPS — it is WSS-only here (see the warning above). This is the most common integration mistake on this chain.
- No batching — the HTTPS endpoint is REST, so there is no JSON-RPC envelope to batch. A JSON array POSTed to
/cosmosreturns-32603(unexpected backend response format), because the LCD never answers a JSON-RPC batch. - Historical state is limited by node pruning (recent heights only).