Authenticated JSON API for the Blocknet privacy blockchain daemon. All private endpoints require Bearer token authentication via a cookie file (`<dataDir>/api.cookie`) written on daemon startup. Public routes (GET-only blockchain queries) are also served unauthenticated when using `--explorer` mode.
Token read from `<dataDir>/api.cookie`. Generated fresh on every daemon startup using `crypto/rand` (32 bytes, hex-encoded = 64 chars). File has 0600 permissions. Deleted on graceful shutdown.
curl -H "Authorization: Bearer $(cat data/api.cookie)" http://127.0.0.1:8332/api/status
Daemon and node status
Lightweight liveness probe. Returns 200 with the current server timestamp. Does not require authentication.
{
"status": "ok",
"timestamp": "2026-03-11T18:30:00Z"
}
Returns node and chain status including peer count, chain height, sync state, mempool summary, and wallet diagnostics (if unlocked).
{
"peer_id": "12D3KooWBLUPjZgAoizTkbNJvHxgHkb2tF1saUhmKBzFfo8zZLfj",
"peers": 8,
"chain_height": 14207,
"best_hash": "0000c3a5b7e2d1f4",
"total_work": 14208,
"mempool_size": 3,
"mempool_bytes": 4821,
"syncing": false,
"identity_age": "2h34m12s",
"wallet": {
"data_version": 1,
"enc_format": "v1",
"kdf_version": 1,
"kdf_memory_mib": 256,
"kdf_iterations": 3,
"kdf_threads": 4,
"created_at": 1710000000,
"view_only": false,
"has_mnemonic": true,
"address_format": "checksummed",
"file_size_bytes": 2048,
"synced_height": 14200
}
}
unauthorizedVerifies an ed25519 signature against a Blocknet stealth address. Does not require a wallet — uses only stateless cryptographic verification. Useful for 'login with Blocknet' flows where any node can validate a signature produced by `POST /api/wallet/sign`. Rate-limited per IP.
{
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"message": "blocknet-auth:1:blocknet.id:a1b2c3d4e5f6:1708531200",
"signature": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
{
"valid": true
}
{
"valid": false
}
{
"error": "invalid address"
}{
"error": "invalid signature: must be 64 bytes hex-encoded"
}{
"error": "message is required"
}{
"error": "verify rate limit exceeded"
}Block, transaction, and mempool queries
Returns a block by numeric height or 64-character hex hash. Includes transaction summaries and confirmation count.
{
"height": 14207,
"hash": "0000c3a5b7e2d1f489a1bc37e5d204f8c612aa9b33e7f04d12b8a9e6c7f50321",
"prev_hash": "0000a1f38e2bc9d7a436ef21c87b3d4e59a0f1b267e3c9d58a2b41f6e7083c19",
"merkle_root": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"timestamp": 1738800120,
"difficulty": 100000,
"nonce": 847291,
"tx_count": 2,
"transactions": [
{
"hash": "c7f2e1d3a4b596870123456789abcdef0123456789abcdef0123456789abcdef",
"is_coinbase": true,
"inputs": 0,
"outputs": 1,
"fee": 0
},
{
"hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"is_coinbase": false,
"inputs": 1,
"outputs": 2,
"fee": 15000
}
],
"confirmations": 1,
"reward": 72325093035
}
{
"error": "id must be a height or 64-char hex hash"
}unauthorized{
"error": "block not found"
}Searches mempool first (fast), then scans the blockchain from tip backwards. Returns the transaction with confirmation count and mempool status.
{
"tx": {
"version": 1,
"inputs": [
{
"key_image": [206,194,102,91,117,127,68,44,128,196,45,250,102,215,110,191,198,108,77,236,91,173,42,44,240,161,206,21,137,3,217,104],
"ring_members": [
[226,131,206,64,181,243,28,67,77,209,63,49,60,73,151,89,90,209,74,106,163,255,119,131,60,185,95,37,147,5,24,172],
[110,193,204,172,204,197,212,189,47,92,19,190,204,227,117,159,115,159,54,160,111,127,196,151,224,41,224,215,131,35,150,164]
],
"ring_commitments": [
[244,65,131,220,148,209,81,144,194,225,99,194,172,101,176,2,181,151,98,87,133,213,118,209,176,204,1,57,103,0,158,85],
[227,105,135,213,239,147,102,10,53,157,38,16,29,213,153,189,151,99,51,202,204,88,135,235,168,65,66,228,199,214,91,184]
],
"pseudo_output": [185,41,236,101,236,26,183,66,110,82,226,90,90,18,56,11,87,242,214,41,217,44,73,158,2,195,168,69,207,102,28,108],
"ring_signature": "gGqM7cNe9fNWJnrrBzqo/CSrAowGo9OFVEUYyxIYr3WVUeAd1XVgO/hXi426JGVYtSk6QEZMLBDCVbV2Uq4br99gnVs4S/4GdsAxeOMpUlXjv4GgF8sKmVFDBZKXlD/8"
}
],
"outputs": [
{
"commitment": [57,12,140,125,114,71,52,44,216,16,15,47,111,119,13,101,214,112,229,142,3,81,216,174,142,79,110,172,52,47,194,49],
"public_key": [183,176,135,22,235,63,193,40,150,185,98,35,23,116,148,40,119,51,194,142,232,186,83,189,181,107,136,36,87,125,83,236],
"range_proof": "UTfDE/BxZuuznHRyDGLMqI4jjrPMqQ47hVuHEzfesKDfO8VhghbfAGS63COpoD+ZntGnzpdBYtfCWZrPAJuSa9yk7uLibfJWK5GrL3iec2VLDBd98yXp1GPE/cx8SwI22XBa7Rl/PulE7aLi2uRR8+aEfo34eozhJ5J4i6ujKUZNdsRObSDU0Knu1B9p18cKwvQDtJjH1nD5cIvf+A7HrM9U70ENyQ0q20XsXRmFwqds6Keswo7XgSnwCRqzciMUD35mCk56QPI6b+6DvFU6U583DZ/Ay2UmfDSaPRWx270jrgbX+jbduetO3lqK9+7fiaV9LI7mfO3CrA79pl35bLWEro+NBWEre9D6e/P75QgvlnHPfJy88rDZqbToipyAdj1ioT1eYm73jZAzY5d0uFuaB0CMFxuVQPs0BpHw9eGuXhqB9DohzfslG01Mmyt/PNVzwubimNucHjJqbIcpUHpYJlAB0ebwlRB2k5DoJHeHZdk6c0yISCQeVJ2T4D/vm86L/OApFN2lgA0udQqJFFnw4o5c3/su8LLRqqQ1UqjS/ZPNEugtoYGlO84A7NMbYLn/4hpoiEOT4Pg+DnpRnwfQL3M67DxO/5WL1PfxfOlKxGFFI43UrogBkJj6TOT3sKrB6aRgesR30hai8sPFTf0SQKkz4TPpB0nRTybwh63LKajCovkSI3iTdC7eMjPjVZkOF6Yclre/3Ep90lxXWSjDe/5JduyC64IE7pNQJeKwmdmA6ZplxPc2ecO3l5cLyowEGf6SdbRwYYBGMRSe4RG6Qy6Xp9RZZkO7i1SD9petOu8mSHPLuy7KB4c/6LyGw743d/EMp3Eg7ZrRO0cXE5v8OzF4RcbovdZP1DL60I8QvW/j43i5Mry3H8uNYT7o",
"encrypted_amount": [81,216,32,197,195,239,128,5],
"encrypted_memo": [58,136,174,57,150,222,80,232,1,134,91,54,152,101,78,191,82,0,165,250,9,57,185,157,122,29,123,40,43,248,35,64,65,243,84,135,216,108,102,159,204,191,224,231,61,126,115,32,173,10,117,112,3,36,30,117,34,16,169,36,121,142,248,109,67,242,124,242,208,97,48,49,220,181,216,210,239,27,50,31,206,173,55,127,98,97,229,71,216,93,142,236,127,38,226,50,25,7,47,121,85,208,248,246,109,205,30,84,194,1,199,135,232,146,216,249,79,97,151,111,29,31,160,29,25,244,80,29]
}
],
"fee": 15000,
"tx_public_key": [194,138,112,166,28,117,16,161,205,137,33,108,161,108,255,202,234,73,135,71,126,134,219,204,185,112,70,252,46,24,56,78]
},
"block_height": 14205,
"confirmations": 3,
"in_mempool": false
}
{
"tx": {
"version": 1,
"inputs": [
{
"key_image": [206,194,102,91,117,127,68,44,128,196,45,250,102,215,110,191,198,108,77,236,91,173,42,44,240,161,206,21,137,3,217,104],
"ring_members": [
[226,131,206,64,181,243,28,67,77,209,63,49,60,73,151,89,90,209,74,106,163,255,119,131,60,185,95,37,147,5,24,172],
[110,193,204,172,204,197,212,189,47,92,19,190,204,227,117,159,115,159,54,160,111,127,196,151,224,41,224,215,131,35,150,164]
],
"ring_commitments": [
[244,65,131,220,148,209,81,144,194,225,99,194,172,101,176,2,181,151,98,87,133,213,118,209,176,204,1,57,103,0,158,85],
[227,105,135,213,239,147,102,10,53,157,38,16,29,213,153,189,151,99,51,202,204,88,135,235,168,65,66,228,199,214,91,184]
],
"pseudo_output": [185,41,236,101,236,26,183,66,110,82,226,90,90,18,56,11,87,242,214,41,217,44,73,158,2,195,168,69,207,102,28,108],
"ring_signature": "gGqM7cNe9fNWJnrrBzqo/CSrAowGo9OFVEUYyxIYr3WVUeAd1XVgO/hXi426JGVYtSk6QEZMLBDCVbV2Uq4br99gnVs4S/4GdsAxeOMpUlXjv4GgF8sKmVFDBZKXlD/8"
}
],
"outputs": [
{
"commitment": [57,12,140,125,114,71,52,44,216,16,15,47,111,119,13,101,214,112,229,142,3,81,216,174,142,79,110,172,52,47,194,49],
"public_key": [183,176,135,22,235,63,193,40,150,185,98,35,23,116,148,40,119,51,194,142,232,186,83,189,181,107,136,36,87,125,83,236],
"range_proof": "UTfDE/BxZuuznHRyDGLMqI4jjrPMqQ47hVuHEzfesKDfO8VhghbfAGS63COpoD+ZntGnzpdBYtfCWZrPAJuSa9yk7uLibfJWK5GrL3iec2VLDBd98yXp1GPE/cx8SwI22XBa7Rl/PulE7aLi2uRR8+aEfo34eozhJ5J4i6ujKUZNdsRObSDU0Knu1B9p18cKwvQDtJjH1nD5cIvf+A7HrM9U70ENyQ0q20XsXRmFwqds6Keswo7XgSnwCRqzciMUD35mCk56QPI6b+6DvFU6U583DZ/Ay2UmfDSaPRWx270jrgbX+jbduetO3lqK9+7fiaV9LI7mfO3CrA79pl35bLWEro+NBWEre9D6e/P75QgvlnHPfJy88rDZqbToipyAdj1ioT1eYm73jZAzY5d0uFuaB0CMFxuVQPs0BpHw9eGuXhqB9DohzfslG01Mmyt/PNVzwubimNucHjJqbIcpUHpYJlAB0ebwlRB2k5DoJHeHZdk6c0yISCQeVJ2T4D/vm86L/OApFN2lgA0udQqJFFnw4o5c3/su8LLRqqQ1UqjS/ZPNEugtoYGlO84A7NMbYLn/4hpoiEOT4Pg+DnpRnwfQL3M67DxO/5WL1PfxfOlKxGFFI43UrogBkJj6TOT3sKrB6aRgesR30hai8sPFTf0SQKkz4TPpB0nRTybwh63LKajCovkSI3iTdC7eMjPjVZkOF6Yclre/3Ep90lxXWSjDe/5JduyC64IE7pNQJeKwmdmA6ZplxPc2ecO3l5cLyowEGf6SdbRwYYBGMRSe4RG6Qy6Xp9RZZkO7i1SD9petOu8mSHPLuy7KB4c/6LyGw743d/EMp3Eg7ZrRO0cXE5v8OzF4RcbovdZP1DL60I8QvW/j43i5Mry3H8uNYT7o",
"encrypted_amount": [81,216,32,197,195,239,128,5],
"encrypted_memo": [58,136,174,57,150,222,80,232,1,134,91,54,152,101,78,191,82,0,165,250,9,57,185,157,122,29,123,40,43,248,35,64,65,243,84,135,216,108,102,159,204,191,224,231,61,126,115,32,173,10,117,112,3,36,30,117,34,16,169,36,121,142,248,109,67,242,124,242,208,97,48,49,220,181,216,210,239,27,50,31,206,173,55,127,98,97,229,71,216,93,142,236,127,38,226,50,25,7,47,121,85,208,248,246,109,205,30,84,194,1,199,135,232,146,216,249,79,97,151,111,29,31,160,29,25,244,80,29]
}
],
"fee": 12000,
"tx_public_key": [194,138,112,166,28,117,16,161,205,137,33,108,161,108,255,202,234,73,135,71,126,134,219,204,185,112,70,252,46,24,56,78]
},
"confirmations": 0,
"in_mempool": true
}
{
"error": "hash must be 64 hex characters"
}unauthorized{
"error": "transaction not found"
}Returns mempool transaction count, total size in bytes, and fee statistics (min, max, average) in atomic units.
{
"count": 5,
"size_bytes": 8420,
"min_fee": 10000,
"max_fee": 25000,
"avg_fee": 14600.0
}
unauthorizedReturns all currently unconfirmed mempool transactions as full transaction objects in a JSON array. Each item matches the same `Transaction` schema returned by `GET /api/tx/{hash}`. Returns an empty array when the mempool is empty.
[
{
"version": 1,
"inputs": [
{
"key_image": [206,194,102,91,117,127,68,44,128,196,45,250,102,215,110,191,198,108,77,236,91,173,42,44,240,161,206,21,137,3,217,104],
"ring_members": [
[226,131,206,64,181,243,28,67,77,209,63,49,60,73,151,89,90,209,74,106,163,255,119,131,60,185,95,37,147,5,24,172],
[110,193,204,172,204,197,212,189,47,92,19,190,204,227,117,159,115,159,54,160,111,127,196,151,224,41,224,215,131,35,150,164]
],
"ring_commitments": [
[244,65,131,220,148,209,81,144,194,225,99,194,172,101,176,2,181,151,98,87,133,213,118,209,176,204,1,57,103,0,158,85],
[227,105,135,213,239,147,102,10,53,157,38,16,29,213,153,189,151,99,51,202,204,88,135,235,168,65,66,228,199,214,91,184]
],
"pseudo_output": [185,41,236,101,236,26,183,66,110,82,226,90,90,18,56,11,87,242,214,41,217,44,73,158,2,195,168,69,207,102,28,108],
"ring_signature": "gGqM7cNe9fNWJnrrBzqo/CSrAowGo9OFVEUYyxIYr3WVUeAd1XVgO/hXi426JGVYtSk6QEZMLBDCVbV2Uq4br99gnVs4S/4GdsAxeOMpUlXjv4GgF8sKmVFDBZKXlD/8"
}
],
"outputs": [
{
"commitment": [57,12,140,125,114,71,52,44,216,16,15,47,111,119,13,101,214,112,229,142,3,81,216,174,142,79,110,172,52,47,194,49],
"public_key": [183,176,135,22,235,63,193,40,150,185,98,35,23,116,148,40,119,51,194,142,232,186,83,189,181,107,136,36,87,125,83,236],
"encrypted_amount": [81,216,32,197,195,239,128,5],
"encrypted_memo": [58,136,174,57,150,222,80,232,1,134,91,54,152,101,78,191,82,0,165,250,9,57,185,157,122,29,123,40,43,248,35,64,65,243,84,135,216,108,102,159,204,191,224,231,61,126,115,32,173,10,117,112,3,36,30,117,34,16,169,36,121,142,248,109,67,242,124,242,208,97,48,49,220,181,216,210,239,27,50,31,206,173,55,127,98,97,229,71,216,93,142,236,127,38,226,50,25,7,47,121,85,208,248,246,109,205,30,84,194,1,199,135,232,146,216,249,79,97,151,111,29,31,160,29,25,244,80,29]
}
],
"fee": 12000,
"tx_public_key": [194,138,112,166,28,117,16,161,205,137,33,108,161,108,255,202,234,73,135,71,126,134,219,204,185,112,70,252,46,24,56,78]
}
]
[]
unauthorizedWalks the entire chain and checks every block's difficulty (LWMA), timestamp rules, and prev-hash linkage. This is an arithmetic-only check (no Argon2id PoW re-hashing), so it completes in seconds. Returns all violations found, or confirms the chain is clean.
{
"height": 14207,
"clean": true
}
{
"height": 14207,
"clean": false,
"violations": [
{
"height": 8042,
"message": "difficulty mismatch: expected 1234 got 5678"
},
{
"height": 8043,
"message": "timestamp not greater than median of last 11 blocks"
}
]
}
unauthorizedPeer connectivity and ban management
Returns the list of currently connected libp2p peers with their peer IDs and remote multiaddrs.
{
"count": 3,
"peers": [
{
"peer_id": "12D3KooWBLUPjZgAoizTkbNJvHxgHkb2tF1saUhmKBzFfo8zZLfj",
"addrs": [
"/ip4/203.0.113.10/tcp/28080"
]
},
{
"peer_id": "12D3KooWN7z3vEqr4C8pMk2axGfRbLVJzqPEasiY4L9DMqFjVnGq",
"addrs": [
"/ip4/198.51.100.22/tcp/28080"
]
},
{
"peer_id": "12D3KooWQe1RkTvGvbFYm6G3bNzdpJRcmAQA4f9bUDkYcFWLdM4P",
"addrs": [
"/ip4/192.0.2.5/tcp/28080"
]
}
]
}
unauthorizedReturns the list of banned peers with ban reason, count, permanence, and expiry time.
{
"count": 2,
"banned": [
{
"peer_id": "12D3KooWMalicious111111111111111111111111111111111111",
"addrs": [
"/ip4/203.0.113.50/tcp/28080"
],
"reason": "sent invalid block",
"ban_count": 3,
"permanent": false,
"expires_at": "2026-02-06T19:30:00Z"
},
{
"peer_id": "12D3KooWMalicious222222222222222222222222222222222222",
"addrs": [
"/ip4/198.51.100.99/tcp/28080"
],
"reason": "excessive invalid transactions",
"ban_count": 5,
"permanent": true
}
]
}
unauthorizedBalance, address, history, and sending. In `--daemon` mode the node starts without a wallet — call `POST /api/wallet/load` first. All other wallet endpoints require a loaded, unlocked wallet (except lock/unlock themselves).
Loads an existing wallet from disk, decrypting with the given password. Primarily used in `--daemon` mode where the app starts without a wallet. If `filepath` is provided, only the basename is used and the file is resolved relative to the configured `--wallet` directory; if omitted, the default wallet path is used. After loading, the wallet is unlocked, all wallet endpoints become available, miner reward keys are pointed at this wallet, and any blocks that arrived before the wallet was loaded are scanned automatically. Can only be called once — returns 409 if a wallet is already loaded.
{
"password": "my-wallet-passphrase",
"filepath": "mywallet.dat"
}
{
"loaded": true,
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"filename": "mywallet.dat"
}
{
"error": "invalid JSON body"
}{
"error": "password must be at least 3 characters"
}{
"error": "invalid filepath"
}{
"error": "unauthorized"
}{
"error": "wrong password"
}{
"error": "wallet file not readable (permission denied)"
}{
"error": "wallet file not found"
}{
"error": "wallet already loaded"
}{
"error": "wallet file is corrupted"
}{
"error": "internal error"
}Generates a new wallet with a fresh BIP39 seed, encrypts it with the given password, and saves it to disk. The wallet is loaded and unlocked in the running daemon. Since this is a brand-new wallet, no chain scanning is needed — the synced height is set to the current chain tip. Can only be called when no wallet is currently loaded (returns 409 otherwise). If `filename` is provided, only the basename is used and the file is placed in the same directory as the configured `--wallet` path; if omitted, the default wallet path is used. Will not overwrite an existing file.
{
"password": "my-wallet-passphrase"
}
{
"created": true,
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"filename": "wallet.dat"
}
{
"error": "invalid JSON body"
}{
"error": "password must be at least 3 characters"
}{
"error": "invalid filename"
}unauthorized{
"error": "wallet already loaded"
}{
"error": "wallet file already exists: wallet.dat"
}{
"error": "internal error"
}Locks and unloads the currently loaded wallet, releasing all in-memory key material. After this call the node returns to the same state as before load was called — all /api/wallet/* endpoints return 503 until a wallet is loaded again. Mining reward keys are cleared. No request body required.
{
"unloaded": true
}
unauthorized{
"error": "no wallet loaded"
}Creates a new wallet from a BIP39 12-word recovery seed, encrypts it with the given password, and saves it to disk. The wallet is loaded and unlocked in the running daemon and the entire blockchain is scanned for outputs belonging to this seed. Can only be called when no wallet is currently loaded (returns 409 otherwise). If `filename` is provided, only the basename is used and the file is placed in the same directory as the configured `--wallet` path; if omitted, the default wallet path is used. Will not overwrite an existing file.
{
"mnemonic": "abandon ability able about above absent absorb abstract absurd abuse access accident",
"password": "my-wallet-passphrase",
"filename": "restored.dat"
}
{
"imported": true,
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"filename": "restored.dat"
}
{
"error": "invalid JSON body"
}{
"error": "mnemonic is required"
}{
"error": "invalid mnemonic phrase"
}{
"error": "password must be at least 3 characters"
}{
"error": "invalid filename"
}unauthorized{
"error": "wallet already loaded"
}{
"error": "wallet file already exists: restored.dat"
}{
"error": "failed to create wallet: invalid mnemonic: checksum mismatch"
}Returns spendable, pending, and total confirmed balance in atomic units (1 BNT = 100,000,000 atomic units). Spendable excludes immature coinbase outputs. Also includes an optional UX-only `pending_unconfirmed` amount (typically change from your most recent send) plus an estimated unlock ETA in seconds, assuming ~5 minute blocks. Requires unlocked wallet.
{
"spendable": 1250000000,
"pending": 72325093035,
"pending_unconfirmed": 0,
"pending_unconfirmed_eta": 0,
"total": 73575093035,
"outputs_total": 14,
"outputs_unspent": 9,
"chain_height": 14207
}
unauthorized{
"error": "wallet is locked"
}{
"error": "no wallet loaded"
}Returns the wallet's public stealth address (base58-encoded spend_pub || view_pub, 64 bytes). Senders derive unique one-time addresses from this. Requires unlocked wallet.
{
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"view_only": false
}
unauthorized{
"error": "wallet is locked"
}{
"error": "no wallet loaded"
}Returns wallet outputs (spendable UTXOs) with amounts, block heights, coinbase flag, and spent status. Requires unlocked wallet.
{
"count": 3,
"outputs": [
{
"txid": "c7f2e1d3a4b596870123456789abcdef0123456789abcdef0123456789abcdef",
"output_index": 0,
"amount": 72325093035,
"block_height": 14200,
"is_coinbase": true,
"spent": false
},
{
"txid": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"output_index": 0,
"amount": 500000000,
"block_height": 14100,
"is_coinbase": false,
"spent": false
},
{
"txid": "f0e1d2c3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d",
"output_index": 1,
"amount": 750000000,
"block_height": 13990,
"is_coinbase": false,
"spent": true,
"spent_height": 14050
}
]
}
unauthorized{
"error": "wallet is locked"
}{
"error": "no wallet loaded"
}Returns every output owned by the wallet with computed status (spent/unspent/pending), confirmations, type, cryptographic keys, and summary counts. Sorted ascending by block height, then txid, then output index. Requires unlocked wallet.
{
"chain_height": 14207,
"synced_height": 14207,
"total": 3,
"spent": 1,
"unspent": 1,
"pending": 1,
"outputs": [
{
"txid": "f0e1d2c3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d",
"output_index": 1,
"amount": 750000000,
"status": "spent",
"type": "regular",
"confirmations": 217,
"block_height": 13990,
"spent_height": 14050,
"one_time_pub": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"commitment": "c7f2e1d3a4b596870123456789abcdef0123456789abcdef0123456789abcdef"
},
{
"txid": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"output_index": 0,
"amount": 500000000,
"status": "unspent",
"type": "regular",
"confirmations": 107,
"block_height": 14100,
"one_time_pub": "d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5",
"commitment": "e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6"
},
{
"txid": "c7f2e1d3a4b596870123456789abcdef0123456789abcdef0123456789abcdef",
"output_index": 0,
"amount": 72325093035,
"status": "pending",
"type": "coinbase",
"confirmations": 7,
"block_height": 14200,
"one_time_pub": "b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9",
"commitment": "f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7"
}
]
}
unauthorized{
"error": "wallet is locked"
}{
"error": "no wallet loaded"
}Builds a privacy-preserving transaction with one or more recipients using RingCT (Pedersen commitments, Bulletproofs range proofs, CLSAG ring signatures with fixed ring size 16), submits to mempool, and broadcasts via Dandelion++. Fee is calculated as max(min_fee, fee_per_byte * tx_size). Note: multi-recipient transactions link all recipients within the same transaction from a graph-analysis perspective. Requires unlocked full wallet (not view-only).
{
"recipients": [
{
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"amount": 500000000
}
]
}
{
"txid": "b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4",
"fee": 15000,
"change": 734850000,
"recipients": [
{
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"amount": 500000000
}
]
}
{
"error": "invalid address: checksum mismatch"
}{
"error": "amount must be greater than 0"
}{
"error": "insufficient spendable balance: have 250000000, need 500000000"
}unauthorized{
"error": "wallet is locked"
}{
"error": "view-only wallet cannot send"
}{
"error": "failed to build transaction: not enough ring members available"
}{
"error": "no wallet loaded"
}Builds a transaction with one or more recipients using caller-specified inputs (coin control). The caller selects which outputs to spend by referencing txid + output_index pairs from GET /api/wallet/outputs. No automatic input selection is performed. Supports dry_run mode to preview fee and change before broadcasting. Optional change_split (1-4) distributes change across multiple outputs for improved back-to-back send concurrency at the cost of reduced privacy. Same fee calculation, ring signatures, and Dandelion++ broadcast as the standard send endpoint.
{
"txid": "c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5",
"fee": 15000,
"change": 234850000,
"change_split": 1,
"input_total": 735000000,
"input_count": 2,
"dry_run": false,
"recipients": [
{
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"amount": 500000000
}
]
}
{
"fee": 15000,
"change": 234850000,
"change_split": 1,
"input_total": 735000000,
"input_count": 1,
"dry_run": true,
"recipients": [
{
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"amount": 500000000
}
]
}
{
"error": "inputs array is required for coin control"
}{
"error": "input 0: output not found (txid abcd...1234, index 0)"
}{
"error": "input 1: immature, has 3 confirmations, needs 10 (txid abcd...1234, index 0)"
}{
"error": "input 0: key image already in mempool (txid abcd...1234, index 0)"
}{
"error": "input 2: duplicate of input 0 (txid b3c4d5...a2b3c4, index 0)"
}{
"error": "insufficient input amount: inputs total 100000, need 500015000 (amount 500000000 + fee 15000)"
}unauthorized{
"error": "wallet is locked"
}{
"error": "view-only wallet cannot send"
}{
"error": "idempotency key reuse with different request"
}{
"error": "idempotency key in progress"
}{
"error": "send rate limit exceeded"
}{
"error": "send busy, retry later"
}{
"error": "internal error"
}{
"error": "no wallet loaded"
}Signs an arbitrary message with the wallet's spend private key (ed25519). Useful for proving address ownership to external services ('login with Blocknet'). Response includes `Cache-Control: no-store`. Requires unlocked full wallet (not view-only).
{
"message": "blocknet-auth:1:blocknet.id:a1b2c3d4e5f6:1708531200"
}
{
"address": "9PNoFCqUa7K8e5JfV2Hs3TBt7kMzRGkPxJ4xVmn5cFbLd1Qy8W6uXo3Z9pNvRwA2hY7sK4mBjE6gC8dF",
"signature": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"message": "blocknet-auth:1:blocknet.id:a1b2c3d4e5f6:1708531200"
}
{
"error": "message is required"
}{
"error": "message must be <= 1024 bytes"
}unauthorized{
"error": "wallet is locked"
}{
"error": "view-only wallet cannot sign"
}{
"error": "internal error"
}{
"error": "no wallet loaded"
}Locks the wallet. All wallet endpoints (balance, address, history, send) will return 403 until unlocked. No request body required.
{
"locked": true
}
unauthorized{
"error": "no wallet loaded"
}Unlocks the wallet with the wallet password. Uses constant-time comparison (`crypto/subtle.ConstantTimeCompare`) to prevent timing attacks.
{
"password": "my-wallet-passphrase"
}
{
"locked": false
}
{
"error": "invalid JSON body"
}{
"error": "incorrect password"
}{
"error": "no wallet loaded"
}Returns the wallet's 12-word BIP39 recovery phrase. Requires Bearer token and wallet password confirmation. Response includes Cache-Control: no-store.
{
"password": "my-wallet-passphrase"
}
{
"mnemonic": "abandon ability able about above absent absorb abstract absurd abuse access accident",
"words": [
"abandon",
"ability",
"able",
"about",
"above",
"absent",
"absorb",
"abstract",
"absurd",
"abuse",
"access",
"accident"
]
}
{
"error": "invalid JSON body"
}{
"error": "incorrect password"
}{
"error": "wallet is locked"
}{
"error": "no recovery seed available"
}{
"error": "no wallet loaded"
}Rescans blocks from the wallet's last synced height to the chain tip, scanning for owned outputs and spent key images. Returns immediately if the wallet is already at the chain tip. Requires loaded, unlocked wallet.
{
"status": "synced",
"synced_height": 14207,
"chain_height": 14207,
"blocks_scanned": 12,
"outputs_found": 1,
"outputs_spent": 0
}
{
"status": "already synced",
"synced_height": 14207,
"chain_height": 14207
}
unauthorized{
"error": "wallet is locked"
}{
"error": "internal error"
}{
"error": "no wallet loaded"
}Derives the deterministic transaction private key to prove a transaction was sent by this wallet. The tx key can be shared with a recipient or third party to verify payment. Works on both full and view-only wallets (uses the view private key). Requires loaded, unlocked wallet.
{
"txid": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}
{
"txid": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"tx_key": "f0e1d2c3b4a5f6e7d8c9b0a1f2e3d4c5b6a7f8e9d0c1b2a3f4e5d6c7b8a9f0e1"
}
{
"error": "txid must be 64 hex characters"
}{
"error": "coinbase transactions have no sender proof"
}unauthorized{
"error": "wallet is locked"
}{
"error": "transaction not found on chain"
}{
"error": "transaction was not sent by this wallet"
}{
"error": "failed to derive tx key"
}{
"error": "no wallet loaded"
}Scans all wallet outputs and groups them by key image. Outputs that share a key image are duplicates caused by a historical self-send key derivation bug — only one output per group can ever be spent, the rest are permanently unspendable (burned). No request body required. Requires loaded, unlocked wallet.
{
"total_outputs": 42,
"unique_key_images": 42,
"failed_key_images": 0,
"duplicate_groups": null,
"total_burned": 0,
"burned_outputs": 0
}
{
"total_outputs": 42,
"unique_key_images": 40,
"failed_key_images": 0,
"duplicate_groups": [
{
"key_image": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"outputs": [
{
"txid": "b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4",
"output_index": 0,
"amount": 500000000,
"spent": false,
"block_height": 1200
},
{
"txid": "c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5",
"output_index": 1,
"amount": 100000000,
"spent": false,
"block_height": 1201
}
],
"burned_amount": 100000000,
"unspendable_count": 1
}
],
"total_burned": 100000000,
"burned_outputs": 1
}
unauthorized{
"error": "wallet is locked"
}{
"error": "no wallet loaded"
}Returns the wallet's view-only key material (spend public key, view private key, view public key). These keys allow monitoring incoming funds and transaction history without spending ability. Requires Bearer token and wallet password confirmation. Response includes Cache-Control: no-store. Not available on view-only wallets.
{
"password": "my-wallet-passphrase"
}
{
"spend_pub": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"view_priv": "f0e1d2c3b4a5f6e7d8c9b0a1f2e3d4c5b6a7f8e9d0c1b2a3f4e5d6c7b8a9f0e1",
"view_pub": "d4c3b2a1e5f6d7c8b9a0e1f2d3c4b5a6e7f8d9c0b1a2e3f4d5c6b7a8e9f0d1c2"
}
{
"error": "invalid JSON body"
}{
"error": "incorrect password"
}{
"error": "wallet is locked"
}{
"error": "this is already a view-only wallet"
}{
"error": "too many attempts; try again later"
}{
"error": "no wallet loaded"
}Argon2id PoW miner control (~2GB RAM per thread)
Returns mining state, thread count, and stats (hashrate, hash count, blocks found, start time) when running. Hashrate and stat fields are omitted when the miner is stopped.
{
"running": true,
"threads": 4,
"hashrate": 2.37,
"hash_count": 8532,
"blocks_found": 12,
"started_at": "2026-02-06T14:00:00Z"
}
{
"running": false,
"threads": 4
}
unauthorizedStarts the Argon2id proof-of-work miner. Each thread allocates ~2GB RAM. No request body required.
{
"running": true
}
unauthorized{
"error": "mining already running"
}Stops the miner. No request body required.
{
"running": false
}
unauthorized{
"error": "mining not running"
}Sets the number of mining threads. Each thread uses ~2GB RAM for Argon2id. Takes effect immediately if the miner is running.
{
"threads": 4
}
{
"threads": 4
}
{
"error": "threads must be >= 1"
}unauthorizedReturns a complete block template ready for proof-of-work solving. Includes a pre-built coinbase transaction (paying to the loaded wallet by default, or to the optional `address` override), selected mempool transactions, and the computed merkle root. The `target` field (hex) is the PoW target that the Argon2id hash must be less than. The `header_base` field (hex) is the 92-byte serialized header without the nonce, used as input to the PoW hash function. The `template_id` field identifies this template and can be used with compact submit payloads (`template_id` + `nonce`) via `POST /api/mining/submitblock`. Requires a loaded wallet (for coinbase keys) but does not require it to be unlocked.
{
"block": {
"header": {
"version": 1,
"height": 14208,
"prev_hash": "0000c3a5b7e2d1f489a1bc37e5d204f8c612aa9b33e7f04d12b8a9e6c7f50321",
"merkle_root": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"timestamp": 1738800240,
"difficulty": 100000,
"nonce": 0
},
"transactions": []
},
"target": "000000000000f4240000000000000000000000000000000000000000000000000",
"header_base": "0100000080370000...",
"reward_address_used": "3wZc3y1Qw4eYpZtGJxkqkV6xG9c2oXHqfJjQ6b3sR5hYhJ8tZz1qvJ1mY1a9o7hV4pYwqH7xG5d5d8cJ8p4",
"template_id": "7b3d2f4a9d11c8ef"
}
{
"error": "invalid JSON body"
}unauthorized{
"error": "no wallet loaded"
}Accepts a solved block (from pool mining or external miner) and adds it to the chain. The block must pass full validation: correct height, prev_hash linking to current tip, valid difficulty, valid Argon2id proof-of-work, valid merkle root, and valid transactions. On success the block is broadcast to all peers and subscribers are notified.
{
"accepted": true,
"hash": "0000d4b5a8e7c3f2910b6e5d4c3a2f1e0d9c8b7a6f5e4d3c2b1a09f8e7d6c5b4",
"height": 14208
}
{
"error": "invalid block: invalid proof of work"
}{
"error": "invalid block: invalid height: expected 14208, got 14209"
}{
"error": "block not accepted (duplicate or stale)"
}unauthorizedReal-time Server-Sent Events stream for new blocks and mining notifications
Server-Sent Events stream for real-time updates. On connection, emits a `connected` event with current chain state. Then streams `new_block` for every new block added to the chain and `mined_block` for blocks mined by this node. Sends SSE comment keepalives every 30s. Write timeout is disabled for this long-lived connection.
connectedSent immediately on connection
event: connected
data: {"chain_height":14207,"syncing":false}
new_blockNew block added to chain
event: new_block
data: {"height":14208,"hash":"0000d4b5a8e7c3f2910b6e5d4c3a2f1e0d9c8b7a6f5e4d3c2b1a09f8e7d6c5b4","timestamp":1738800240,"tx_count":3}
mined_blockBlock mined by this node
event: mined_block
data: {"height":14208,"hash":"0000d4b5a8e7c3f2910b6e5d4c3a2f1e0d9c8b7a6f5e4d3c2b1a09f8e7d6c5b4","reward":72325093035}
keepaliveSSE comment sent every 30s to keep connection alive
: keepalive
curl -N -H "Authorization: Bearer $(cat data/api.cookie)" http://127.0.0.1:8332/api/events
unauthorizedDangerous administrative operations (data purge, etc.). These are irreversible and require password confirmation.
Deletes all blockchain data from disk. Requires password verification and explicit confirmation. Stops the daemon, removes the data directory, then shuts down the API server. A restart is required after this operation. This is irreversible.
{
"password": "my-wallet-passphrase",
"confirm": true
}
{
"success": true,
"message": "blockchain data purged successfully, restart required"
}
{
"error": "confirmation required (set confirm: true)"
}{
"error": "incorrect password"
}{
"error": "failed to purge blockchain data: permission denied"
}unauthorized
{
"error": "invalid JSON body"
}
{
"error": "block not found"
}
{
"error": "wallet is locked"
}
{
"error": "no wallet loaded"
}
Machine-readable OpenAPI 3.1 spec available at:
api_openapi.json