Asentum

Reference

Node API Reference

Every HTTP route a node serves, with real responses · Estimated read time: 20 minutes

Accurate as of node 0.8.1.

TL;DR

Every Asentum node serves one HTTP API on its RPC port. It has two parts: plain REST routes (this page) and Ethereum-style JSON-RPC on POST / (see the JSON-RPC Reference). The REST routes are what the wallets, the SDK, @asentum/connect, the explorer and the Operator app use.

New to tip reads and finality? Read Fast Confirmations first. It explains the three states a transaction goes through and how to show each one.

Hosts

Base URLWhat it is
https://testnet.asentum.comPublic gateway. Every route on this page plus JSON-RPC on POST /. Load balanced over the public RPC nodes; one client IP always lands on the same node.
https://explorer.asentum.comThe explorer website. JSON-RPC works on POST /. REST routes work under /rpc, for example https://explorer.asentum.com/rpc/v3/heads. GET / is the explorer itself.
http://<server-ip>:8545Your own VPS node. Same routes, no gateway in front. See Run Your Own RPC.
http://127.0.0.1:9545The node inside the Operator desktop app. Only reachable from the same computer.

The examples on this page use https://testnet.asentum.com. Do not point scrapers or backfills at the core validator nodes directly: they are watched and an IP that hammers them is blocked. Run your own node for heavy work (see Run Your Own RPC).

Conventions

  • JSON in, JSON out. POST bodies are JSON (send Content-Type: application/json). Every response is JSON except the explorer pages.
  • Numbers are decimal strings. Heights, balances, nonces and gas are strings like "571252" so big values survive JSON. Amounts are in wei (1 ASE = 1018 wei). JSON-RPC uses hex quantities instead.
  • Timestamps are milliseconds. A block header's timestamp is Unix time in ms, for example "1792490329086".
  • Hashes and raw bytes are 0x hex. Transaction hashes are 32 bytes (64 hex characters).
  • Errors are usually HTTP 200. A missing receipt, a missing block, a bad address and a rejected transaction all answer 200 with error or accepted: false, reason. Real non-200 codes: 404 for an unknown route, 429 for rate limits, 204 on some sync routes, 500 for a body that is not valid JSON, 503 from /ready or while a node shuts down.
  • Finalized or tip. The finalized height is final and never changes. The tip is the newest block on the best chain, usually about 3 blocks ahead. Some routes read the tip by default, some only finalized data. Each route below says which.
  • CORS is open. Access-Control-Allow-Origin: * on every route, so a web page can call the API directly. The gateway allows the Content-Type and Authorization request headers. A node on its own allows Content-Type, Accept and X-Requested-With.
  • gzip. Large sync responses are gzipped when the client sends Accept-Encoding: gzip (fetch in Node and browsers does this for you).

Addresses

Every route that takes an address accepts an ase1 address or the same 20 bytes as 0x hex. Responses are not consistent yet, so convert before you show anything to a user (toAse1 in @asentum/connect, or bech32 with prefix ase over the same 20 bytes):

Returned as ase1Returned as 0x hex
/balance, /public-key, /asentum/account, /validators (address), /chain and /block headers (proposer), block transactions (to), /slashing/tombstones (slashingContract), /api (faucetAddress)Receipts (sender, recipient, and addresses inside event data), /participation, /v3/committee, /consensus/liveness, /consensus/state, /genesis

Contract arguments are different again: POST /view passes args to the contract exactly as you send them, and contracts store accounts as lowercase 0x hex. See POST /view.

Rate limits and caching

There are two layers of limits: the public gateway, and the node itself. Your own node only has the node layer.

WhereLimitWhen you hit it
Gateway, per IPAbout 25 requests a second, with a burst of 100. Applies to every route that is not cached.HTTP 429 with an HTML body and no Retry-After header. Back off and retry.
Node: block reads, per client IPBurst of 240, then 4 a second. Counts GET /block/*, /block-raw/*, /receipts/* and the JSON-RPC block methods (eth_getBlockByNumber, eth_getBlockByHash, eth_getBlockTransactionCountByNumber/ByHash).HTTP 429, JSON {"error":"too many block requests from this address, slow down"} and a Retry-After header in seconds.
Node: /v3/proposalBurst of 1,500, then 4 a second. Only charged when a block is served.Same 429 as block reads.
Node: transactionsOff by default. An operator can turn on a per-IP budget for POST /tx, /tx/batch and JSON-RPC sends (ASENTUM_TX_IP_PER_SEC, burst ASENTUM_TX_IP_BURST, default 30).429 {"error":"too many transactions from this address, slow down"}. A /tx/batch larger than the burst never passes.
Node: /probe/reachable10 a minute per IP.429 {"reachable":false,"error":"too many probes, try again in a minute"}.
Node: POST /v3/precommitBurst of 20, then 10 a second per socket IP. Body capped at 64 KB.429 with accepted: false, or 413 for a large body.

Behind the gateway the node sees your real IP (the gateway is a trusted proxy), so the node limits are per client, not shared. Polling one receipt a second is well inside every limit.

Cached responseCacheWhere
GET /chain1 sGateway (X-Cache-Status header)
GET /validators2 s (5 s on explorer.asentum.com/rpc), plus 500 ms in the nodeGateway and node
GET /participation2 s (5 s on explorer.asentum.com/rpc), per query stringGateway
GET /metadata30 sGateway
GET /v3/heads250 ms in the node, Cache-Control: max-age=1Node
GET /v3/proposal, GET /v3/commit?quorum=minFinalized heights: Cache-Control: public, max-age=300Node

The cached gateway routes can be a second or two behind the chain. If you need the exact current height, use /v3/heads. The gateway gives each request 30 seconds before it fails with a 504.

Chain and health

GET/v3/heads

The finalized height and the tip (newest block on the best chain) in one tiny response. The cheapest way to drive a block counter or decide which heights to fetch.

Request

curl -s https://testnet.asentum.com/v3/heads

Response

{"finalized":"571252","tip":"571255"}
  • finalized is the same height as eth_blockNumber and /chain. tip is usually 2 to 4 blocks ahead.
  • A transaction in a block at or below finalized can never change. Between finalized and tip it can still move to another block (rare). See Fast Confirmations.
GET/chain

Chain id, the finalized height, this node's mempool size and the finalized block header.

Request

curl -s https://testnet.asentum.com/chain

Response

{
  "chainId": "1423",
  "height": "571241",
  "mempoolSize": 33,
  "latestHeader": {
    "parentHash": "0x17063346ef1453...", "stateRoot": "0x4e4fe3fb8538bf...",
    "transactionsRoot": "0x7122dea29dd4f4...", "receiptsRoot": "0xd2755b10f4287d...",
    "number": "571241", "timestamp": "1792490301086",
    "gasLimit": "30000000", "gasUsed": "937818", "baseFeePerGas": "1",
    "proposer": "ase13mqx732wza4lvtv7e7a985mlxft6tdwgduvcky",
    "lastCommitBitmap": "0xfeea56f79aed2b7e7dfd1a0aa0000000"
  }
}
  • height is the finalized height, not the tip. Cached for 1 second on the gateway.
  • mempoolSize is this node's own mempool. Each node has its own.
  • There is no block hash in the header JSON. Get it from eth_getBlockByNumber or from a receipt's blockHash.
GET/health

Liveness probe. Answers as long as the HTTP server is up.

Request

curl -s https://testnet.asentum.com/health

Response

{"status":"ok"}
  • It does not check sync, peers or block production. Use /v3/heads and compare with the public gateway for that.
GET/ready

Readiness probe meant to report whether the chain is advancing: 200 with status ready, or 503 with status stale.

Request

curl -s https://testnet.asentum.com/ready

Response

{"status":"ready","height":"571241","lastBlockAgeSec":0}
  • Do not rely on it in 0.8.1. It compares the clock in seconds with a block timestamp in milliseconds, so lastBlockAgeSec is always 0 and it always answers ready, even on a stalled node. To detect a stall, check that /v3/heads keeps moving.
GET/api

Node identity: chain id, finalized height and the node's dev faucet address.

Request

curl -s https://testnet.asentum.com/api

Response

{"name":"asentum-node","version":"0.0.0-alpha.0","chainId":"1423","height":"571241","faucetAddress":"ase1hm4ja2dgczv2lm599z2uwr8szu0zsz8twu69nm"}
  • version is a fixed placeholder, not the node release. There is no API route that reports the release; on a VPS run asentum-validator status.
GET/metadata

Chain details in the EIP-3085 shape (wallet_addEthereumChain), plus a few extras.

Request

curl -s https://testnet.asentum.com/metadata

Response

{
  "chainId": "0x58f",
  "chainName": "Asentum Testnet",
  "nativeCurrency": {"name":"Asentum","symbol":"ASE","decimals":18},
  "rpcUrls": ["https://testnet.asentum.com"],
  "blockExplorerUrls": ["https://testnet.asentum.com"],
  "chainIdDecimal": "1423",
  "currentBlock": "571241",
  "faucetUrl": "https://testnet.asentum.com/dev/faucet"
}
  • Cached for 30 seconds on the gateway, so currentBlock lags.
  • faucetUrl is not a public faucet: the node route is off by default. Get test ASE from the airdrop dashboard (see Get Test ASE).
  • The real block explorer is https://explorer.asentum.com.
GET/genesis

The genesis spec a new node uses to join: chain id, gas limit, base fee, initial accounts and validators, genesis hash and state root.

Request

curl -s https://testnet.asentum.com/genesis

Response

{"chainId":"1423","gasLimit":"30000000","baseFeePerGas":"1",
 "initialAccounts":[{"address":"0xbeeb2ea9a8c098afee852895c70cf0171e2808eb","balance":"2000000000000000000000000"}, ...],
 "initialValidators":[...], "initialAseHolders":[...], "genesisHash":"0x...", "genesisStateRoot":"0x..."}
  • About 17 KB. Addresses are 0x hex. A node without a stored spec answers {"error":"no genesis spec available", ...}.

Accounts

GET/balance/<address>

Balance and nonces of an account or contract, read at the tip.

ParameterMeaning
addressase1 address (or 0x hex of the same 20 bytes).

Request

curl -s https://testnet.asentum.com/balance/ase1v0myp2de3dhj3crvkhxqlnjaw2mvp64a9efkpl

Response

{"address":"ase1v0myp2de3dhj3crvkhxqlnjaw2mvp64a9efkpl","balance":"460922160143819003814070","nonce":"0","pendingNonce":"0"}
  • balance is in wei. nonce is the account's nonce at the tip. pendingNonce also counts this sender's transactions queued in this node's mempool. Sign your next transaction with pendingNonce so several sends in a row get n, n+1, n+2.
  • A bad address answers 200 with {"error":"invalid address","message":"..."}. An address that has never been used answers balance and nonce 0.
  • There is no /nonce route. This is the nonce route.
GET/asentum/account/<address>

The full account record: balance, nonce, code hash and storage root.

ParameterMeaning
addressase1 address (or 0x hex).

Request

curl -s https://testnet.asentum.com/asentum/account/ase1v0myp2de3dhj3crvkhxqlnjaw2mvp64a9efkpl

Response

{"address":"ase1v0myp2de3dhj3crvkhxqlnjaw2mvp64a9efkpl","exists":true,
 "balance":"461078849858191139118984","nonce":"0",
 "codeHash":"0x331901b8e05f019598da59892039dd65f5ef4deb407ad68410ad8dc41e8c7770",
 "storageRoot":"0x410cd2facf28f99becdedc72d0c14d4354ae8920680cec6c5fce7409647f4685",
 "height":"571334"}
  • An unknown address answers {"address":"ase1...","exists":false,"height":"..."}.
  • codeHash is the BLAKE3 hash of the contract source, so you can check a contract against its published source (see Verifying Contracts). For accounts that are not contracts it is all zeros.
GET/public-key/<address>

Whether the chain already has this account's public key on record. Once it does, a wallet may send smaller transactions without the key (key-once, live since block 528,000).

ParameterMeaning
addressase1 address (or 0x hex).

Request

curl -s https://testnet.asentum.com/public-key/ase1r3m77x6eyxt0emxg9jepm8ah7gy8kxmw90w5ty

Response

{"address":"ase1r3m77x6eyxt0emxg9jepm8ah7gy8kxmw90w5ty","recorded":true,
 "keyHash":"0x1c77ef1b592196fcecc82cb21d9fb7f2087b1b6e3ab844b1892e3b1c844f3529",
 "keylessActive":true,"keylessFromBlock":"528000","nextBlock":"571405","canOmitKey":true}
  • Send a key-less transaction only when canOmitKey is true. Otherwise it is rejected with sender public key not on record.

Blocks

GET/block/<number>[?tip=1]

A block with its decoded transactions and receipts.

ParameterMeaning
numberBlock height, decimal.
tipOptional. 1 (or true) also answers heights above the finalized head, from the pending block on the node's best chain. Default 0: finalized blocks only.

Request

curl -s https://testnet.asentum.com/block/571252
curl -s "https://testnet.asentum.com/block/571255?tip=1"

Response

{
  "header": {"parentHash":"0xd4b6923e...","stateRoot":"0x9f806bb4...","number":"571252",
             "timestamp":"1792490329086","gasUsed":"446457","baseFeePerGas":"1",
             "proposer":"ase1vcfv3x57vu2gdxm6ergmctzu9xgp62lvt242ah", ...},
  "transactions": [
    {"kind":"call",
     "body":{"chainId":"1423","nonce":"8","maxPriorityFeePerGas":"0","maxFeePerGas":"1",
             "gasLimit":"20000000","to":"ase1v0myp2de3dhj3crvkhxqlnjaw2mvp64a9efkpl","value":"0","dataSize":118},
     "call":{"method":"swapExactIn","args":["1","0xc24044dccea3ba8b362e1c85fa16ddc658022269","45933719102783","9301718868854625"]},
     "publicKeyLength":1952,"signatureLength":3309}
  ],
  "receipts": [ {"txHash":"0x3261a75d...","txIndex":0,"success":true, ...} ],
  "finalized": true
}
# with ?tip=1 for a height above finality:
{"header":{...},"transactions":[...],"receipts":[...],
 "finalized":false,"confirmations":"2","auraHash":"0xc8e549d4cdbb5557..."}
  • Without ?tip=1, a height above the finalized head answers 200 {"error":"not found","number":"571255"}. So does a height this node does not have (see History).
  • kind is transfer, deploy or call. For calls, call is the decoded method and args. Public keys and signatures are left out, only their sizes are shown. A key-less transaction has keyless: true and a sender.
  • Transactions in this JSON have no hash. Match them to receipts by position (txIndex), or use the receipts' txHash.
  • Counts against the node block-read budget. A browser navigating to /block/<n> gets the explorer page instead of JSON (see below).
GET/block/<number>/receipts[?tip=1]

Only the receipts of a block. Smaller than the full block; what indexers want.

ParameterMeaning
numberBlock height, decimal.
tipOptional, as for /block. Default 0.

Request

curl -s https://testnet.asentum.com/block/571252/receipts

Response

{"blockNumber":"571252","receipts":[{"txHash":"0x3261a75d...","blockNumber":"571252","txIndex":0,
  "sender":"0x1c77ef1b592196fcecc82cb21d9fb7f2087b1b6e","recipient":"0x63f640a9b98b6f28e06cb5cc0fce5d72b6c0eabd",
  "kind":"call","success":true,"gasUsed":"88573","events":[...],"returnValue":"9443894822196084"}, ...],
 "finalized":true}
  • A height that is not available answers {"blockNumber":"...","receipts":[]} with no finalized field. An empty list does not always mean an empty block: check that finalized is present.
GET/block-raw/<number> and /raw-block/<number>

The block as SSZ bytes in hex, for nodes and tools that decode the wire format themselves.

Request

curl -s https://testnet.asentum.com/block-raw/571252
curl -s https://testnet.asentum.com/raw-block/571252

Response

{"number":"571252","bytes":"0xd4b6923e48f3d8b5..."}
{"rawBlock":"0xd4b6923e48f3d8b5..."}
  • Two routes, same bytes, different field names. /block-raw counts against the block-read budget; /raw-block does not. Missing block: {"error":"not found"} (200) on /block-raw, HTTP 404 on /raw-block.
  • Unlike /block, both also answer a height above the finalized head with the pending block, and nothing in the response says it is not final. Compare the height with /v3/heads.

Transactions and receipts

POST/tx

Submit one signed transaction. This is the only way to submit: eth_sendRawTransaction is not supported.

ParameterMeaning
rawTxThe signed transaction, SSZ encoded, as a 0x hex string. The SDK, @asentum/connect and the wallets build and sign it (ML-DSA-65). There is no unsigned or JSON transaction format.

Request

curl -s -X POST https://testnet.asentum.com/tx -H 'content-type: application/json' \
  -d '{"rawTx":"0x..."}'

Response

{"accepted":true,"txHash":"0x6c91b3cec4c0cf9da739221d2e8c1fac73df528c1225c918ce6135b02dd4d5cd"}
{"accepted":false,"reason":"stale nonce: account is at 153, tx has 152"}
  • accepted: true means this node checked the transaction and put it in its mempool. It has not run yet and it is not in a block. It can still fail, or be dropped from the mempool. Poll /receipts to know what happened. Do not tell a user it is done because of accepted.
  • A rejected transaction has no txHash and never reaches the chain. Show the reason.
  • Reasons you will see: stale nonce: account is at N, tx has M (nonce already used), nonce too far ahead: ..., duplicate (this exact transaction is already in the mempool), duplicate nonce (another transaction with that nonce is queued), insufficient balance for value plus gas, gas limit too low for a contract call: min 50000 ..., wrong chainId: ..., invalid signature, sender public key not on record: ..., mempool full, sender queue full, blocked: this wallet is blocked on the testnet for spam, and for bad input missing rawTx (expected hex string), invalid rawTx hex: ..., invalid rawTx SSZ: ....
  • The node forwards an accepted transaction to the block producers. There is no route that lists the mempool or a pending transaction (txpool_* and eth_pendingTransactions do not exist). If a transaction never gets a receipt, re-sign it with the same nonce and submit again.
  • Submit and poll through the same host. On the gateway one IP always reaches the same node, which keeps pendingNonce consistent.
POST/tx/batch

Submit several signed transactions in one request. They are admitted one by one in the order given, so nonce order is kept.

ParameterMeaning
transactionsArray of {"rawTx":"0x..."} objects.

Request

curl -s -X POST https://testnet.asentum.com/tx/batch -H 'content-type: application/json' \
  -d '{"transactions":[{"rawTx":"0x..."},{"rawTx":"0x..."}]}'

Response

{"accepted":1,"rejected":1,"total":2,"results":[
  {"accepted":true,"txHash":"0x..."},
  {"accepted":false,"reason":"duplicate nonce"}]}
  • Each result has the same shape as POST /tx. One rejection does not stop the rest, so a gap in nonces can leave later transactions waiting.
  • A body without a transactions array answers HTTP 400 {"error":"expected { transactions: [{ rawTx }] }"}.
GET/receipts/<txHash>[?tip=0]

The receipt of a transaction: whether it ran, in which block, gas, events and return value.

ParameterMeaning
txHash32-byte transaction hash, 0x hex.
tipOptional. Default 1: also returns receipts from blocks that are on the best chain but not final yet (finalized: false). 0: finalized receipts only.

Request

curl -s https://testnet.asentum.com/receipts/0x3261a75d9804a1f92a08d88ca0878ad5edac0bf1e63c408d8f2181a6ffcd7ea1

Response

{
  "txHash": "0x3261a75d9804a1f92a08d88ca0878ad5edac0bf1e63c408d8f2181a6ffcd7ea1",
  "blockNumber": "571252",
  "txIndex": 0,
  "sender": "0x1c77ef1b592196fcecc82cb21d9fb7f2087b1b6e",
  "recipient": "0x63f640a9b98b6f28e06cb5cc0fce5d72b6c0eabd",
  "kind": "call",
  "success": true,
  "gasUsed": "88573",
  "events": [{"name":"Transfer","data":{"from":"0x1c77ef1b...","to":"0x63f640a9...","value":"45933719102783"}}],
  "returnValue": "9443894822196084",
  "finalized": true,
  "confirmations": "8",
  "blockHash": "0x5c21659e3aa85b139eece5ac1e7dca7f184695cd2ee377427ddd8e69f481e90d"
}
# not in a block (yet), HTTP 200:
{"error":"receipt not found","txHash":"0xabab...abab"}
  • The success field is success (true or false). There is no status field on this route. status: "0x1" is the JSON-RPC receipt (eth_getTransactionReceipt). Code that checks r.status === 1 against /receipts reports every transaction as failed.
  • "Not found" is HTTP 200. A receipt exists only when the body has a blockNumber. A failed transaction also has an error field (its revert reason), but it has a blockNumber too, so test for blockNumber, not for error.
  • finalized: false means the block is on the best chain but not final. In rare cases that block loses to a sibling: the receipt disappears, the transaction goes back to the mempool and normally lands again in a later block, with a new blockNumber and blockHash (and possibly a different result). Only finalized: true is permanent. While not final the receipt also has auraHash.
  • confirmations is tip height minus blockNumber, plus 1.
  • sender, recipient and addresses in event data are 0x hex. For a deploy, recipient is the new contract.
  • Wait for this receipt, not for a block height. A transaction can land several blocks after you sent it. The copy-paste polling helper is in Fast Confirmations.
  • Counts against the node block-read budget (a burst of 240, then 4 a second). Poll about once a second.

Contract reads

POST/view

Run a contract method read-only. No transaction, no gas paid, nothing is written.

ParameterMeaning
contractContract address, ase1 (or 0x hex).
methodMethod name, a string.
argsOptional array of arguments, passed to the method exactly as sent.
blockTagOptional. "tip" (default), "latest" or "pending": the newest block. "finalized" or "safe": the finalized state. Anything else is rejected. Block numbers are not accepted: there are no historical state reads.

Request

curl -s -X POST https://testnet.asentum.com/view -H 'content-type: application/json' \
  -d '{"contract":"ase1v0myp2de3dhj3crvkhxqlnjaw2mvp64a9efkpl","method":"getPool","args":["3"]}'

Response

{"ok":true,
 "returnValue":"{\"id\":\"3\",\"token0\":\"0x50cb8d861050ad0052959e0f942c5347842346f1\",\"reserve0\":\"1046355455215355449482246\", ...}",
 "events":[],"gasUsed":"21800","blockNumber":"571273","finalized":false}
# with "blockTag":"finalized"
{"ok":true,"returnValue":"...","events":[],"gasUsed":"21800","blockNumber":"571271","finalized":true}
# errors (HTTP 200)
{"ok":false,"reason":"contract method not found: nope"}
{"ok":false,"reason":"invalid \"blockTag\" (expected \"latest\", \"tip\" or \"finalized\")"}
  • Address arguments must be 0x hex. Contracts store accounts as lowercase 0x hex (that is what msg.sender is), and /view does not convert args. getValidator on the staking contract returns null for an ase1 argument and the record for its 0x form. viewCall in the SDK and client.view in @asentum/connect convert ase1 arguments for you; with raw /view use ase1ArgsToHex.
  • returnValue is whatever the method returns. Many contracts return a JSON string (as getPool does above), so you may need JSON.parse. BigInts come back as decimal strings.
  • Reads the tip by default, so right after your transaction is in a block, /view already shows its effect. Behind a load balancer, check blockNumber is at least your receipt's block before trusting the read.
  • events lists what the method would have emitted. Nothing is stored.
  • A body that is not valid JSON answers HTTP 500 {"error":"internal","message":"invalid JSON body: ..."}.

Validators and consensus

GET/validators

Every bonded validator with stake and committee state, plus the current epoch and entry window.

Request

curl -s https://testnet.asentum.com/validators

Response

{"count":812,"stakingContract":"ase1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpf05455",
 "epoch":{"head":"571247","current":"1904","blocksPerEpoch":"300","entryWindowBlocks":"100",
          "currentStart":"571200","currentEnds":"571500","currentWindowOpensAt":"571400","nextWindowOpensAt":"571400"},
 "validators":[{"address":"ase1n2kslv6ra3nkgxec2u9vntvzcrkrlpcwp6yl3a","stake":"20000000000000000000000000",
   "bondedAt":"0","status":"active","activeAtBlock":"10","pubKeySize":3906,
   "broadcastUrl":"http://204.168.132.194:8545","committeeState":"signing",
   "consecutiveMisses":0,"lastVotedHeight":"571249","nextCommitteeEntryAt":null}, ...]}
  • committeeState is one of signing, waiting_epoch_entry, dormant, pending_bond or tombstoned. signing means the validator has voted and is not dormant. It does not mean it holds a committee seat in this epoch: the committee is 100 seats drawn each epoch (see /v3/committee).
  • About 260 KB with 800+ validators. Cached 2 s on the gateway and 500 ms in the node, so poll it every few seconds at most.
GET/participation[?lookback=N]

Who actually signed recent blocks: per validator signed blocks, ratio and last signed block over the last N blocks.

ParameterMeaning
lookbackOptional. Blocks to scan, 1 to 10,000. Default 1,000.

Request

curl -s "https://testnet.asentum.com/participation?lookback=50"

Response

{"head":"571247","scannedFrom":"571198","lookback":50,"totalValidators":812,
 "signing":109,"idle":0,"dormant":703,"recentWindow":50,
 "validators":[{"address":"0x9aad0fb343ec67641b38570ac9ad82c0ec3f870e","stake":"20000000000000000000000000",
   "signedBlocks":50,"participationRatio":1,"lastSignedBlock":"571247","status":"signing"}, ...]}
  • Addresses are 0x hex. status here is signing (signed in the last 100 blocks, or the whole window if shorter), idle or dormant, judged from the blocks themselves.
  • Expensive on the node for large lookbacks. Cached per query string for 2 s on the gateway.
GET/v3/committee[?epoch=N]

The voting committee of an epoch in canonical order (the order commit bitmaps use), the leader base, and whether the committee lottery chose it.

ParameterMeaning
epochOptional epoch number. Default: the current epoch (finalized height / 300).

Request

curl -s https://testnet.asentum.com/v3/committee

Response

{"epoch":"1904","lottery":true,
 "committee":["0x1cb5e65c853b8dfe4c3202a728d84e902c426a79","0x72b2064cdd4c02e21577f22baee166e276aff5f2", ...100 entries],
 "leaderBase":["0x1cb5e65c853b8dfe4c3202a728d84e902c426a79", ...]}
  • Addresses are 0x hex. An epoch the node cannot compute answers HTTP 404 {"error":"..."}.
GET/v3/finalized?height=H

Whether a height is finalized on this node, and the Aura hash of the block finalized there.

ParameterMeaning
heightRequired block height.

Request

curl -s "https://testnet.asentum.com/v3/finalized?height=571000"

Response

{"height":"571000","finalized":true,"auraHash":"0x03da607b14ab33a66148463ae6168160d11bcbe7cfaac740d2d8311da9db00d5"}
{"height":"571443","finalized":false}
GET/consensus/liveness

The node's liveness tracker: last vote height and consecutive misses for every tracked validator, the dormancy threshold and the core validators.

Request

curl -s https://testnet.asentum.com/consensus/liveness

Response

{"head":"571247","livenessWindow":"100","maxConsecutiveMisses":50,
 "baked":["0x1cb5e65c...","0x72b2064c...","0x86f62ed9...","0x9aad0fb3..."],
 "tracked":[{"address":"0x004b8ddacfd6d729644080ee30021f1472ccf697","lastVotedHeight":"569999","consecutiveMisses":0,"baked":false}, ...],
 "certPersist":{...},"voteBroadcast":{...}}
  • About 40 KB. Addresses are 0x hex. This is the data behind committeeState in /validators.
GET/slashing/tombstones

Validators that have been slashed and tombstoned.

Request

curl -s https://testnet.asentum.com/slashing/tombstones

Response

{"count":0,"slashingContract":"ase1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz8upr6t","tombstones":[]}
GET/consensus/state

Deprecated. A snapshot from the old v2 BFT engine, kept so old tools do not break.

Request

curl -s https://testnet.asentum.com/consensus/state

Response

{"height":"550198","round":"0","phase":"propose","proposer":"0x9aad0fb343ec67641b38570ac9ad82c0ec3f870e",
 "validatorCount":83,"quorumThresholdStake":"53786493388964146162534705",
 "prevoteCounts":[],"precommitCounts":[],"committedBlockHash":null}
  • Do not use it. It does not follow the live chain: in the sample above it is about 21,000 blocks behind, and it can refresh rarely or go backwards. Use /v3/heads for heights, /v3/committee for the committee and the block header's proposer for who produced a block.

Governance

Read-only wrappers around the governance contract. Voting and proposing are contract calls sent with POST /tx. Background in Protocol Governance.

RouteReturns
GET /governance/proposals{"proposals":[...]}: the newest proposals (up to 50).
GET /governance/proposal/<id>{"proposal":{...},"amendments":[...]}. An unknown id gives {"proposal":null,"amendments":[]}.
GET /governance/locked/<address>{"address":"ase1...","locked":"0"}: ASE locked in votes, in wei.
GET /governance/withdrawable/<address>{"address":"ase1...","locked":"0","withdrawable":"0","positions":[]}.
GET /governance/libraries{"libraries":[]}. Library approval is disabled, so always empty.
GET /governance/library/<name>{"library":null}.
curl -s https://testnet.asentum.com/governance/locked/ase1hm4ja2dgczv2lm599z2uwr8szu0zsz8twu69nm
{"address":"ase1hm4ja2dgczv2lm599z2uwr8szu0zsz8twu69nm","locked":"0"}

On failure each route answers 200 with an empty value and an error field.

Node operator and sync routes

These routes are how nodes sync from each other and how pull-mode validators (Operator app, nodes behind NAT) get blocks and send votes. They are public because nodes need them, but they are internal: the formats are binary wire frames and can change between releases without notice. Apps should not use them.

RouteWhat it does
GET /v3/proposal?height=H{"available":true,"height":"H","wire":"0x...","auraHash":"0x..."}: the block frame applied at H. HTTP 204 when this node does not have it yet. The main sync route for pull-mode nodes.
GET /v3/commit?height=H[&quorum=min]The GRANDPA commit certificate for H as JSON (round, target hash, signer bitmap, signatures). 204 when H is not finalized here or the certificate has aged out (the node keeps about 1,100 rounds).
POST /v3/precommitBody {"wire":"0x<vote frame>"}. A committee member sends its signed precommit. Answers {accepted, folded?, reason, finalized}. Signature and committee membership are always checked.
GET /v3/route-statsRequest and byte counters for the sync and vote routes on this node, plus relay and sync-pool state.
GET /v3/vote-metricsPer-voter precommit timing on a producing node. 404 when v3 is not engaged.
GET /probe/reachable?url=<http(s) URL>Asks this node to fetch <url>/metadata and says whether it answered as a chain node: {"reachable":true,"latencyMs":255,"chainId":"0x58f"}. Used by the Operator app to check that a validator's address is reachable. Public addresses only, 10 a minute per IP.
GET /libp2p-addrs{"enabled":true,"peerId":"","addresses":[]} on current nodes (blocks and votes travel over ANT on port 9000).
GET /cron-status{"enabled":true,"envVar":null}: whether this node runs scheduled contract calls.
GET /consensus/proposal, GET /consensus/votesOld v2 pull routes. Answer {"available":false}.
POST /consensus/proposal, POST /consensus/voteOld v2 push routes. Answer {"accepted":false,"reason":"v2 consensus is off while v3 is engaged"}.
GET /debug/stateFull state dump for debugging. 404 unless the node runs with ASENTUM_DEBUG_ENDPOINTS=1.

Faucet and dev routes

POST/dev/faucet

A node's built-in dev faucet. Off by default: a node answers HTTP 404 {"accepted":false,"reason":"faucet not enabled on this node"} unless its operator sets ASENTUM_DEV_FAUCET=1, which only makes sense on a local devnet.

ParameterMeaning
toRecipient address (ase1 or 0x hex).
amountAmount in wei, as a string. At most 100,000 ASE per drip.
  • For test ASE, use the airdrop dashboard (see Get Test ASE). The SDK's requestFaucet() and faucet() call this route and only work against a devnet node with it turned on.
  • On testnet.asentum.com and explorer.asentum.com, POST /dev/faucet is a separate service: the one-time validator bond drip the installer and the Operator app use. It is not a general faucet. explorer.asentum.com/api/dev/faucet is retired and answers HTTP 410.
RouteStatus
POST /dev/produce-blockOld v2 route. Does nothing on the live chain and answers {"skipped":true,"reason":"not the scheduled proposer"}.
GET /playgroundRetired. The gateway redirects it to https://ide.asentum.com.

Explorer pages on a node

A node also serves a small built-in explorer. A browser navigation (or Accept: text/html without Sec-Fetch-Dest) to these paths gets HTML; a fetch() gets the JSON described above:

  • GET /: the explorer page. POST / is JSON-RPC.
  • GET /block/<n>: HTML for a browser, block JSON for fetch.
  • GET /address/<ase1 or 0x> and GET /tx/<hash>: HTML only. For data use /balance/<address> and /receipts/<hash>. A fetch to these paths answers 404.
  • GET /governance, /governance/<id>, /governance/libraries: HTML for a browser.

On the public hosts, use explorer.asentum.com, which has its own full index.

What does not exist

Some routes are mentioned in older posts and tools but are not served by any node:

  • GET /nonce/<address>: use /balance/<address> (nonce and pendingNonce).
  • GET /tx/<hash> as JSON: use /receipts/<hash>, or eth_getTransactionByHash for the transaction body.
  • A mempool or pending-transaction listing: there is none, on REST or JSON-RPC.
  • GET /metrics (Prometheus): not served. Monitor with /v3/heads, /validators and the node journal (see Monitoring & Logs).
  • WebSocket (/ws, eth_subscribe): not served. Poll instead.
  • Historical state: /view, /balance and JSON-RPC state reads only know the tip and the finalized state, not an older block.

An unknown route answers HTTP 404 {"error":"not found","method":"GET","path":"/nonce/ase1..."}.

History, indexing and backfills

  • Nodes do not keep full history. A node serves blocks and receipts from the point it was synced from a snapshot onward. Below that, /block answers not found, /receipts answers receipt not found and eth_getTransactionByHash returns null, even for transactions that did happen. On 20 October 2026 the public pool served roughly the last 40,000 blocks, and the start differs from node to node.
  • There is no public archive RPC and no bulk export. The explorer keeps its own full index for its pages; it is not a public API.
  • For an indexer, page by block range, not by transaction lists. Walk heights with /block/<n>/receipts (receipts and events, decoded) or eth_getLogs (at most 10,000 blocks per call, finalized blocks only). Block ranges never shift as new transactions arrive.
  • Stay inside the limits. Block reads on a node are a burst of 240, then 4 a second per IP. Backfilling through the public gateway is slow by design. Run your own node next to your indexer (see Run Your Own RPC) and keep it running so it collects history from then on.
  • Contract deployments are receipts with kind: "deploy"; recipient is the new contract and sender the deployer. There is no separate registry route.
  • Live window. To show activity before finality, also read the heights between finalized and tip with ?tip=1 and replace them when a block hash changes. The full recipe is in Fast Confirmations: Indexers.

Read next