Skip to main content

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.

SurfacePathServes
Owner/v2/ownerNode administration, eight methods
Foreign/v2/foreignChain reads, transaction submission, block templates, seventeen 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:

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 sync state is an owner-surface call, and needs the node credential.

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:536, /v2 at api/src/handlers.rs:135 and api/src/handlers.rs:155.

The difference is where the operation is named.

/v1/v2
StyleRESTJSON-RPC 2.0
Operation named bythe URL paththe method field in the body
HTTP verbGET, POST to mutatePOST
URLsone per operation/v2/foreign, /v2/owner, /v2/tor
Resultthe payloadthe payload inside result.Ok
CredentialBasic auth across the /v1 prefixper 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:446.

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 19 patterns, three of them wildcards.

RouteVerbJSON-RPC equivalent
/v1/GETnone, this is the route index
/v1/statusGETget_status, owner
/v1/chainGETget_tip, foreign
/v1/chain/validateGETvalidate_chain, owner
/v1/chain/compactPOSTcompact_chain, owner
/v1/blocks/<hash|height>GETget_block, foreign
/v1/headers/<hash|height|commit>GETget_header, foreign
/v1/chain/kernels/<excess>?min_height=&max_height=GETget_kernel, foreign
/v1/chain/outputs/byids?id=GETget_outputs, foreign
/v1/chain/outputs/byheight?start_height=&end_height=GETget_outputs, foreign
/v1/txhashset/rootsGETnone
/v1/txhashset/lastoutputs?n=GETnone
/v1/txhashset/lastrangeproofsGETnone
/v1/txhashset/lastkernelsGETget_last_n_kernels, foreign
/v1/txhashset/outputs?start_index=&max=GETget_unspent_outputs, foreign
/v1/txhashset/merkleproof?n=GETinclude_merkle_proof on get_outputs, foreign
/v1/poolGETget_pool_size and get_stempool_size, foreign
/v1/pool/push_txPOSTpush_transaction, foreign
/v1/peers/allGETget_peers, owner
/v1/peers/connectedGETget_connected_peers, owner
/v1/peers/<addr>GETget_peers with a peer_addr, owner
/v1/peers/<addr>/banPOSTban_peer, owner
/v1/peers/<addr>/unbanPOSTunban_peer, owner
/v1/peers/onion_addressesGETget_onion_addresses, owner
/v1/versionGETget_version, foreign
/v1/mining/block_templateGETget_block_template, foreign
/v1/kerneldownloadGETnone

A /v1 call, which takes the node credential across the whole prefix:

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 on a local usernet chain at height 1439 on 2026-08-24.

Full method reference

Source

Next