Baklava

The query surface

Twenty-one queries over plain HTTP. Enough for a wallet to work without trusting the node it is talking to.

the public node
curl https://rpc.baklava.network/v1/head --output head.bin

Answers are binary, not JSON

Every answer is the canonical encoding of the thing it describes — application/octet-stream. That is not awkwardness for its own sake: one answer has exactly one encoding, and therefore exactly one hash. A JSON view of the same answer would be a second encoding of it, and two encodings drift.

So clients decode. This site decodes the head in the browser to show the height on its front page; baklava account and baklava receipt do the same thing from a terminal and check the proof while they are at it.

An answer never verifies against itself

Every Verify takes the root or the epoch record from outside — one the wallet already trusts. An answer checked against its own contents verifies every time, including the times a node made it up.

A standalone receipt proves that a quorum of the epoch's frozen set signed. Only a receipt checked against a header chain proves the committee did.

The routes

GET /v1/headThe tip: its header, and the certificate that committed it.
GET /v1/header/{height}One header, with the previous leader's VRF output.
GET /v1/block/{height}A block and the transactions in it.
GET /v1/account/{address}A balance and nonce, with the proof that folds to the state root.
GET /v1/participant/{address}A registry entry: stake, seniority, reliability, the rule version it says it can run.
GET /v1/paramsThe consensus parameters as the chain holds them, upgrade schedule included.
GET /v1/readinessHow much of this epoch's frozen set is behind each rule version. The one answer with no proof.
GET /v1/token/{id}A token's record: supply, decimals, creator, labels.
GET /v1/token/{id}/balance/{address}One holder's balance of one token.
GET /v1/collection/{id}A collection's record: size, creator, metadata commitment, labels.
GET /v1/collection/{id}/item/{index}Who owns one item — with both leaves, because an item that never moved belongs to the creator.
GET /v1/collection/{id}/item/{index}/listingThe offer on one item, if it is for sale: the seller, the price, the asset and the expiry.
GET /v1/pool/{id}A swap pool: the pair, the shares in issue, and where the reserves are held.
GET /v1/pool/{id}/share/{address}One provider's share of one pool.
GET /v1/proposal/{id}One governance proposal, with its running tally proved against the state root.
GET /v1/proposalsThe ids of every open proposal. The only answer here that carries no proof.
GET /v1/receipt/{txid}A transaction's receipt — the self-proving copy.
GET /v1/receipts/{address}The receipts a node holds for an address.
GET /v1/epoch/{epoch}An epoch record: roots, counts, the aggregate key.
GET /v1/epoch/{epoch}/setThe frozen member list, in address order.
GET /v1/epoch/{epoch}/member/{index}One member of a frozen set.
POST /v1/submitHand a signed transaction to the mempool.

What is deliberately not in it

No authentication, no TLS, no rate limit and no CORS headers. Those are transport concerns and they belong to whatever stands in front — this network's node binds its RPC to the loopback and nginx supplies all four. The chain does not care who is asking, because a wrong answer is caught by the proof it fails rather than by knowing who sent it.

There is also no search, no index of transactions by anything but address, and no history beyond the retention window. Users carry their own receipts; a node that serves nobody can run without the local indexes entirely.

The faucet is a different service

It answers JSON, because a faucet answer proves nothing and is verified by nobody — what it hands back is a transaction id, and the chain is what says whether that transaction happened.

faucet
curl https://faucet.baklava.network/v1/status
curl -X POST https://faucet.baklava.network/v1/request \
     -H 'Content-Type: application/json' -d '{"address":"bkx1..."}'

It answers 200 with a transaction id, 429 with the seconds until the next request is allowed, 400 for an address whose checksum did not match, or 503 when it has run dry.