Node API
The node serves JSON-RPC 2.0 on one listener, bound to 127.0.0.1 port 3413 by
default, split across two surfaces.
| Surface | Path | Serves |
|---|---|---|
| Owner | /v2/owner | Node administration, 8 methods |
| Foreign | /v2/foreign | Chain reads, transaction submission, block templates, 18 methods |
Credentials, and which of these expects one, are covered once in authentication and TLS.
The same listener also serves a REST surface under /v1. See
the v1 REST surface.
Which JSON-RPC method lives where
/v2/owner is node administration only:
get_status, validate_chain, compact_chain, get_peers, get_connected_peers, ban_peer,
unban_peer, get_onion_addresses.
/v2/foreign is everything else, including every chain read and transaction submission:
ready_for_txs, get_header, get_block, get_blocks, get_tip, get_version, get_kernel,
get_last_n_kernels, get_outputs, get_unspent_outputs, get_pmmr_indices, get_pool_size,
get_stempool_size, get_unconfirmed_transactions, push_transaction, get_block_template,
finalize_block_template, submit_block.
So reading a block is a foreign-surface call, and it takes no credential on a default install:
curl -s -d '{"jsonrpc":"2.0","method":"get_tip","params":[],"id":1}' \
http://127.0.0.1:3413/v2/foreign
Checking whether the node is synced is a foreign-surface call too. ready_for_txs returns
{"ready_for_txs": true} only when the sync state is no_sync, false otherwise, and needs no
credential:
curl -s -d '{"jsonrpc":"2.0","method":"ready_for_txs","params":[],"id":1}' \
http://127.0.0.1:3413/v2/foreign
The full status, with height, peers and the named sync state, is get_status on the owner surface. It
normally needs the node credential, but one plain
get_status call is answered without it.
Response shapes
total_difficulty is an object keyed by proof-of-work algorithm, not an integer:
{
"total_difficulty": {
"cuckaroo": 0,
"cuckatoo": 1234,
"randomx": 5678,
"progpow": 9012
}
}
Block headers describe their proof with two fields: proof, a string naming the algorithm, and
solution, a tagged union whose shape follows that algorithm.
Status includes supply and max_supply in whole EPIC rather than freemen, and
blocks_to_next_halving as a block count. Reward steps are not all halvings; see
emission.
Kernels appear in two shapes depending on the method. get_block returns a flattened form, while
get_kernel and get_last_n_kernels return the raw type with an externally tagged features field.
Handle both.
Mining over HTTP
The foreign surface offers a three-step block submission flow as an alternative to Stratum:
get_block_template, finalize_block_template, submit_block. It is JSON-RPC over HTTP. See
Stratum.
The v1 REST surface
The node serves REST under /v1 and JSON-RPC under /v2, from the same process on the same port.
The numbers name two interface styles, not two generations: /v1 is registered at
api/src/handlers.rs:692, /v2 at
api/src/handlers.rs:132 and
api/src/handlers.rs:152.
The difference is where the operation is named.
/v1 | /v2 | |
|---|---|---|
| Style | REST | JSON-RPC 2.0 |
| Operation named by | the URL path | the method field in the body |
| HTTP verb | GET, POST to mutate | POST |
| URLs | one per operation | /v2/foreign, /v2/owner, /v2/tor |
| Result | the payload | the payload inside result.Ok |
| Credential | Basic auth across the /v1 prefix, except GET /v1/version | per surface |
Both surfaces return the same payloads. GET /v1/status and get_status on /v2/owner produce
identical bodies, so the JSON-RPC pages document the response shapes for
both.
GET /, GET /v1/ and GET /v2/ return a list of v1 routes, from
api/src/handlers.rs:606. GET /v1/ needs the credential like the
rest of the prefix.
Routes
Verbs are as the node's route index reports them. The right-hand column is the JSON-RPC method that returns the same thing, and its surface.
Every v1 route and its JSON-RPC equivalent
The router registers 18 patterns, 6 of them wildcards: blocks/*, headers/*, chain/outputs/*,
chain/kernels/*, txhashset/* and peers/**.
| Route | Verb | JSON-RPC equivalent |
|---|---|---|
/v1/ | GET | none, this is the route index |
/v1/status | GET | get_status, owner |
/v1/chain | GET | get_tip, foreign |
/v1/chain/validate | GET | validate_chain, owner |
/v1/chain/compact | POST | compact_chain, owner |
/v1/blocks/<hash|height> | GET | get_block, foreign |
/v1/headers/<hash|height|commit> | GET | get_header, foreign |
/v1/chain/kernels/<excess>?min_height=&max_height= | GET | get_kernel, foreign |
/v1/chain/outputs/byids?id= | GET | get_outputs, foreign |
/v1/chain/outputs/byheight?start_height=&end_height= | GET | get_outputs, foreign |
/v1/txhashset/roots | GET | none |
/v1/txhashset/lastoutputs?n= | GET | none |
/v1/txhashset/lastrangeproofs | GET | none |
/v1/txhashset/lastkernels | GET | get_last_n_kernels, foreign |
/v1/txhashset/outputs?start_index=&max= | GET | get_unspent_outputs, foreign |
/v1/txhashset/merkleproof?n= | GET | include_merkle_proof on get_outputs, foreign |
/v1/pool | GET | get_pool_size and get_stempool_size, foreign |
/v1/pool/push_tx | POST | push_transaction, foreign |
/v1/peers/all | GET | get_peers, owner |
/v1/peers/connected | GET | get_connected_peers, owner |
/v1/peers/<addr> | GET | get_peers with a peer_addr, owner |
/v1/peers/<addr>/ban | POST | ban_peer, owner |
/v1/peers/<addr>/unban | POST | unban_peer, owner |
/v1/peers/onion_addresses | GET | get_onion_addresses, owner |
/v1/version | GET | get_version, foreign. The one /v1 route that needs no credential |
/v1/mining/block_template | GET | get_block_template, foreign |
A /v1 call, which takes the node credential. Without -u, or on a node with no api_secret_path, it
returns 401:
curl -s -u epic:$(cat ~/.epic/main/.api_secret) http://127.0.0.1:3413/v1/status
{
"protocol_version": 2,
"user_agent": "MW/Epic 4.0.3",
"connections": 0,
"tip": {
"height": 1439,
"last_block_pushed": "9abbd80483f9b082a9362ebac0aba5619bdba7cf647cb15f5ed33102faf3cd1b",
"prev_block_to_last": "6ceed7ff0ff7da1d44b01dc03189edeb1323bfa6d3625768520dd1a0498a0735",
"total_difficulty": {"cuckaroo": 1440, "cuckatoo": 1440, "randomx": 1440, "progpow": 1440}
},
"sync_status": "no_sync",
"supply": 23024,
"max_supply": 21000000,
"blocks_to_next_halving": 479521
}
Captured from node 4.0.3 on a local usernet chain at height 1439 on
2026-08-24. A 4.1.0 node puts its own version in user_agent.
Full method reference
11 methods. Sync readiness, blocks, headers, kernels, outputs and the tip.
8 methods. Status, peers, validation and compaction.
4 methods, one of them irreversible.
3 methods. Mining over HTTP instead of Stratum.
Source
api/src/owner_rpc.rs:29defines the 8 owner methodsapi/src/foreign_rpc.rs:38defines the foreign methodsapi/src/types.rsdefines every response shapeapi/src/auth.rsis the Basic auth middleware