Rand Protocol
Documentation
Reference

Explorer API

A summary of the RandScan REST API and WebSocket feed at randscan.org - what a shielded chain's explorer can serve, the endpoints, and the rate limits - with a link to the full guide.

Use the explorer’s API to read chain 21 (the live chain since 2026-10-12; the explorer re-indexed from its genesis) from a script, a bot or a backend without running a node. The full guide with every field is in the explorer repository, randscan.org/docs/api.md; this page is the summary.

base URLhttps://randscan.org/api/v1
WebSocketwss://randscan.org/ws
anonymous60 requests per minute per IP
with an API key600 requests per minute; keys from randscan.org/dashboard, sent as Authorization: Bearer rsk_… or X-API-Key

What a shielded chain’s explorer can show

There are no accounts, balances, senders or recipients anywhere in this API, and since chain 14 no public asset on a bundle: a transfer of RAND and a transfer of any RPL token are the same shape. What it serves is every block; every transaction’s hidden-asset bundle as published (anchor, four nullifiers, four commitments, fee, burn_a, burn_r, burn_asset, time, proof and envelope sizes, and since chain 17 the auth_commit and the auth proof’s size); the action a transaction carried and its public fields, including an RPL token’s registration, mints and burns, the bridge-governance actions and an RPL-2 invoke’s state transition; the RPL token registry; a program’s cells and vault; the commitment tree leaf by leaf; the nullifier set; the validator register; the supply audit; the bridge’s public state, including its mint pause and PQ guardian set. Which asset a transfer moved is shown only to a viewing key or a transaction key, in the browser. GET /accounts/:address answers 410 { "error": "no_accounts" }.

Conventions: amounts are decimal strings of units. An amount whose asset_index names a token other than RAND (index 0) is in that token’s own smallest unit, not RAND’s nine decimals; resolve the index through GET /tokens/:id before dividing. registration_fee and next_index are the two fields the explorer serves as plain JSON numbers; hashes, program ids, commitments and nullifiers are 64 lowercase hex characters; validator addresses are base58; heights are decimal integers from 0; only committed blocks are indexed, so a block in the API is final. Lists take page (from 1) and limit (1 to 100, default 20), return { "data": [...], "pagination": { page, limit, total, total_pages, has_next, has_prev } }, newest first. Errors are { "error", "message", "code" } with 400, 404, 410, 429 or 500.

Endpoints

method and pathreturns
GET /healthexplorer status and indexer lag
GET /statschain id, height, view, tree size, validator counts, total stake, supply, program count, average block time, epoch, the genesis hash and the node’s build; hc_bundle and hc_auth; limits (the five genesis caps, then envelope_bytes, hardening_v6, hc_auth, the genesis gas_price and byte_price, gas_metering, bundle_gas_limit, adjust_bps, and program_state on a node since v0.6.8); gas_prices, the tip’s live prices. limits does not carry v0.6.8’s other new fields (binding_domain, proof_window_blocks, the price ceilings, admission_by_vote, testnet) nor v0.8.0’s (hc_auth_multisig, fee_rules, perps, multisig): read those from the node’s rand_getLimits. On chain 21 chain_id reads 21 and the build 0.8.0
GET /supplythe node’s supply audit verbatim, including the four vesting_* counters, all "0" on chain 21, whose genesis has no vesting section, RPL-2’s program_rand_out and program_rand_held, the RAND paid out of program vaults and the RAND they still hold, and on a v0.8.0 node base_fees_burned (the bundle floors burned under chain 21’s fees section), the perps_* pair and the five multisig_* counters (multisig_issued is the 100,000 RAND treasury)
GET /bridgethe bridge’s public state: emitter, emitters, guardian_set_index, guardians, pq_guardians, mint_paused, pause_nonce, list_nonce, pause_key, registration_fee, burn_sequence, next_index (null since chain 14), rotation_nonce, rules_v2 (with global_minted_in_window and global_mint_headroom), min_inbound_sequence, assets, and endpoints, the explorer’s own rendering of each emitter as its source chain prints it. It does not serve the node’s v0.6.8 fees, rotation_rules or pending_rotations: read those from rand_getBridgeState
GET /bridge/assetsone row per backing: the registry row (index, chain, token, asset_id, locked, minted_today, mint_cap_per_day, and on a v0.6.8 node minted_in_window, mint_window_secs and mint_headroom, the largest deposit the caps admit now) joined with symbol, name, decimals and backings, and the indexed tallies. Per backing: burns, burned, outstanding (the registry’s locked), and deposits/deposited only when the token has one backing (null otherwise: a deposit names the token it minted, not the coin locked for it). Per token, identical on every row with the same index: token_deposits, token_deposited, token_burns, token_burned, first_height, last_height; count each index once when totalling
GET /bridge/tokensthe token allowlist, a static list: USDT and USDC on Ethereum, BSC, Tron and Solana, with USDC on Tron discontinued
GET /tokensthe whole RPL token registry as cached from the node: enabled, registration_fee, next_index, tokens
GET /tokens/:idone token by registry index, 64-hex id or rpl1… text form, plus deploy_tx and supply_history; 404 when none matches
GET /nodesthe explorer’s node and its peers, with geolocation
GET /proversthe delegated provers the explorer knows of (its own list; the chain keeps no record of them): whether each answers its prover_info, its capacity and fee, and where its hosts are
GET /blocks?page&limit&proposer, GET /blocks/latest?limit, GET /blocks/:idblocks, by height or hash
GET /transactions?page&limit&kind&height&validator&program, GET /transactions/latest, GET /transactions/:hashtransactions; kind is transfer, mint, deploy, call, bond, unbond, withdraw, bridge_attest, bridge_burn, register_token, token_mint, set_authority, token_burn, pause_mints, unpause_mints, register_bridged_token, list_backing, invoke. There is no token_transfer: a transfer of any RPL token is transfer
GET /transactions/:hash/envelopesthe notes a transaction created with their envelopes: the bundle’s four slots, dummies included, plus the chain-computed notes a bridge_attest deposit, a token_mint, a register_token’s initial mint or an invoke’s payouts append; for a call, h_in and the sealed input transcript
GET /envelopes?from_leaf&limitleaves with envelopes, oldest first, up to 1,000 per page, for a history scan
GET /notes?page&limit, GET /notes/:idtree leaves, by commitment or leaf index
GET /nullifiers/:nfthe transaction that published a nullifier
GET /validators, GET /validators/:addressthe register, with share_percent, blocks_proposed, last proposed height
GET /programs?page&limit, GET /programs/:iddeployed programs (base_pc, words_len, code_hash, public_words_len, public_digest) with call and invoke counts; a program’s recent calls and invokes, and its program_state, read live from the node: vault (per asset), the first 100 cells in key order, and cells_next
GET /programs/:id/cells?after&limita page of the program’s cells in key order, live from the node (limit 1 to 1,000, default 100): { "cells", "next" }; 404 on a chain without a program_state section
GET /search?q=blocks, transactions, programs, notes, nullifiers and validators
curl -s https://randscan.org/api/v1/stats
curl -s https://randscan.org/api/v1/tokens/1
curl -s https://randscan.org/api/v1/transactions/8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666

A transaction summary (a faucet mint of 10 RAND at height 102,197 of chain 18):

{
  "hash": "a20b…feb5", "height": 102197, "block_hash": "f362…a06f", "tx_index": 0,
  "kind": "mint", "fee": "0", "timestamp_ms": 1790777106034,
  "has_bundle": false, "program": null, "validator": "EdrEC2QRQrQF64iRXxF9927jNj6RidiHHByzx5xD6F1e",
  "amount": "10000000000", "asset_index": null
}

amount is filled only for the kinds with a public amount — mint, bond, unbond, withdraw, bridge_attest, bridge_burn, token_mint, token_burn, and a register_token with an initial mint — and is null for a transfer, whose asset_index is always null too. has_bundle is false for mint, unbond, withdraw, pause_mints and unpause_mints, which carry no bundle and pay no fee. The detail adds chain_id, bundle, and per kind: a deploy’s words_len; a call’s call_proof_len, input_envelope_len and receipt (tx, program, tier, outputs, height, index, h_in, h_pub); a bond’s registered; an unbond’s or withdraw’s action_nonce; a bridge attestation’s attestation_len, recipient, note_time, deposit_r, commitment, pq_signers; a bridge burn’s relayer_fee, to_chain, bridge_to, bridge_token; an RPL action’s token_action (the action’s own fields, tagged by kind), with recipient, note_time, deposit_r for a minted note and action_nonce for a token_mint or set_authority; a bridge-governance action’s bridge_governance, with pq_signers on all but pause_mints; an invoke’s call_proof_len, input_envelope_len, receipt and transition (the node’s rendering: the cells read and written, the inflow, and every pays and mints note with its recipient, time, r and cm). A v0.6.8 kind this explorer build does not know (admit_validator, slash_equivocation, the _v2 rotations, cancel_rotation) is other.

Since chain 20, with bridge fees, a bridge_attest’s and a bridge_burn’s amount is the gross: the amount the guardians signed, or the amount the bundle burned. The explorer does not serve the net deposit, the released amount or the fee note; read them from the node’s rand_getTransaction (deposit_amount, release_amount, fee_note) and rand_getBridgeBurn. The burn of 0.999 zUSD at height 2,899 reads "amount": "99900000" here; the guardians signed a release of 99800100.

The bundle in a transaction detail is the hidden-asset bundle, with no asset field and no second bundle on a burn. This one paid for the call in the curl example above, at height 98,335 of chain 18; that transaction does not exist on chain 21, where the third curl answers 404:

"bundle": {
  "anchor": "b814…b1ed",
  "nullifiers": ["49d4…a766", "3363…61ea", "aac0…fcfc", "546c…3efd"],
  "commitments": ["b52b…4f7b", "9ddd…0448", "5fa7…1630", "2827…8343"],
  "fee": "6191437", "burn_a": "0", "burn_r": "0", "burn_asset": 0, "time": 98185,
  "proof_len": 1504260, "envelope_len": [1860, 1860, 1860, 1860],
  "auth_commit": "0bda…6512", "auth_proof_len": 1367303
}

auth_commit and auth_proof_len are split authorisation (chains 17 and later, where limits.hc_auth is set): the bundle proof is made from the viewing key and publishes auth_commit, and a second, small proof over the spend key, bound to the same transaction, must match it. Both proofs are reported by length only. Every envelope on chains 20 and 21 is 1,860 bytes (limits.envelope_bytes) and carries an encrypted memo; chains up to 17 sealed 1,348 bytes. A call’s declared gas limit is a public value of its proof, not a field of the receipt, so the explorer does not show it per transaction; the fee it paid is in fee.

burn_a is the private asset burned, non-zero only on a token_burn, a bridge_burn or an invoke that deposits or burns a token, with burn_asset naming the registry index; burn_r is RAND burned, non-zero only on a bond or an invoke that deposits RAND into the program’s vault.

On chain 21, as on chain 20, zUSD (“Shielded USD”, eight decimals) sits at index 1, listed in the genesis with all seven backings (registered_at 0, so deploy_tx is null) and carried over from chain 14 under the same asset id. GET /bridge/assets therefore returns seven rows under index 1. Chain 20 saw eleven more tokens registered (five on its first day, at indices 2 to 6, three of them with a program as mint authority); none was carried to chain 21, whose genesis lists zUSD alone, so GET /tokens on chain 21 starts with one row until something is registered again. On chain 21 GET /bridge reports rules_v2 with a global mint cap of 4,000 zUSD ("400000000000") per 86,400-second window, rotation_nonce 0, burn_sequence 14 at genesis (13 on chain 20), and a min_inbound_sequence of 3 for source chains 2 and 4, 5 for source chain 3 and 7 for source chain 5 (3, 3, 3 and 7 on chain 20; 1 and 4 on chain 19): the genesis replay floor, the lowest lock sequence a source chain’s attestation may carry to be minted here. On chain 14 it was registered at height 256 by a register_bridged_token, with the other six backings added by list_backing transactions.

Opening envelopes in the browser

An envelope is public chain data, and the explorer holds no key. Its transaction page and History page open envelopes in the browser with a WebAssembly build of the node’s own code (crates/randscan-viewing): paste a viewing key (nk, 64 hex) to see every note that party sent or received, a transaction key to open one payment, a call key to open one call’s inputs, or a wallet key file, of which only the derived viewing key is kept. An opened note is verified by recomputing its commitment. Its disclosed asset is the token registry index, resolved through GET /tokens for the symbol and decimals; this is the only place an amount is tied to an asset for a transfer. A dummy slot opens for no key and reads the same as a note that is not yours. Nothing about a key goes over the network; to build the same tool, fetch /envelopes and /transactions/:hash/envelopes and use the crate.

WebSocket feed

Connect to wss://randscan.org/ws and subscribe to blocks, transactions or stats:

{ "type": "subscribe", "channel": "blocks" }
{ "type": "new_block", "block": { … BlockSummary … } }
{ "type": "new_transaction", "transaction": { … TransactionSummary … } }
{ "type": "stats_update", "stats": { … } }

Send { "type": "ping" } every 30 seconds through proxies. The feed has no replay: on a drop, reconnect and backfill with GET /transactions?height=.

Running your own

Everything here is served by the open-source explorer in randprotocol/randscan.org; the indexer needs only a node’s rand_* JSON-RPC and a PostgreSQL database.

Last verified against fullnode commit c0878c3f (chain 21) on 2026-10-12, and randscan commit fffa404 (docs/api.md), the live API at randscan.org, 2026-09-20, the live API at randscan.org on chain 18, 2026-09-30, the live API at randscan.org on chain 19, 2026-10-01, randscan commit 4390731 (docs/api.md: RPL-2, BRG-19 and `/provers`) and the live API at randscan.org on chain 20, 2026-10-01; `/stats` on chain 21, 2026-10-12. Where the code and this page disagree, the code is right; tell us.