api
Every response carries a normalised freshness envelope plus the live capability set. Errors follow RFC 7807 with a stable machine-readable error_code. Routes that depend on a derive consumer are capability-gated; absent capabilities return 503 capability_unavailable rather than guessing a response.
The {network} path segment is one of mainnet, testnet, or regtest (whichever the deploy serves). It is required on every per-network endpoint; there is no fallback. Process-level endpoints (/api/v1/healthz, /api/v1/openapi.json, /api/v1/stream) omit the segment.
{
"data": { /* endpoint-specific payload */ },
"freshness": {
"network": "mainnet" | "testnet" | "regtest",
"tip_height": 12345,
"tip_hash": "00...",
"derive_lag_blocks": 0,
"capability_version": "explorer.block.summary_v1",
"fetched_at_millis": 1750000000000
},
"capabilities": ["explorer.server_info_v1", "explorer.transaction.detail_v1", ...]
}The envelope is mirrored on response headers (X-Network, X-Tip-Height, X-Capability, X-Capabilities) so agents can branch on freshness without parsing the JSON body. X-Network always matches the {network} segment in the request URL.
/api/v1/{network}/networkNetwork identity, tip height, freshness, and capability set/api/v1/{network}/search?q=...Typed search across blocks, transactions, and address candidates. Shielded inputs always return private_by_design/api/v1/{network}/blocks?limit=20Recent block summaries with ZIP-317 fee floor, sizes, and counts/api/v1/{network}/blocks/{height_or_hash}Block detail including transaction ids, reorg context, and coinbase reward/api/v1/{network}/transactions/{transaction_id}Public facts: status, privacy shape, component counts, ZIP-317 floor, paid fee (transparent only). Raw bytes are not part of any typed read./api/v1/{network}/transactions/recent?limit=8Newest-first projection of recently mined transactions/api/v1/{network}/mempoolMempool snapshot: counts, total bytes, privacy distribution/api/v1/{network}/mempool/activity?limit=50Recent mempool entries with ZIP-317 floor and paid fee where safe/api/v1/{network}/mempool/events?window_seconds=300Rolling counts of added / mined / invalidated / suppressed events. Pair with /api/v1/stream for per-event delivery/api/v1/{network}/fees/summary?lookback=50Aggregated ZIP-317 conventional fee floors across recent blocks/api/v1/{network}/value-poolsPer-pool totals (transparent, Sapling, Orchard, Sprout)/api/v1/{network}/transparent-addresses/{address}Confirmed balance, mempool delta, and UTXOs for a transparent address/api/v1/{network}/transparent-addresses/{address}/activity?limit=50Newest-first confirmed activity rows with prevout resolution status/api/v1/{network}/broadcastBroadcasts a raw transaction. Body: { raw_transaction_hex, network }. Rate-limited 5/min/source/api/v1/{network}/payment-disclosures/verifyVerifies a ZIP-311 payment disclosure. Body: { payment_disclosure_hex }. Disclosure payloads are never logged/api/v1/healthzProcess-level liveness probe. Lists every configured network and per-network upstream reachability/api/v1/streamWebSocket multiplexer. Subscribe to topics (chain.committed_v1, mempool.added_v1/invalidated_v1/mined_v1/suppressed_v1/unknown_v1, capability.changed_v1) with a JSON envelope; each event carries its network in the envelopeErrors are application/problem+json (RFC 7807). Every response carries a stable error_code string drawn from the closed vocabulary documented in docs/reference/error-vocabulary.md. The HTTP status is derived from error_code via a single closed table (e.g. not_found → 404, capability_unavailable → 503, rate_limited → 429). Requesting a network not configured on this deploy returns network_not_configured → 400.
const network = "mainnet"; // or "testnet" / "regtest"
const response = await fetch(
`/api/v1/${network}/transactions/${transactionIdHex}`,
{ headers: { accept: "application/json" } }
);
if (!response.ok) {
const problem = await response.json();
// problem.error_code is one of the stable codes documented above
throw new Error(problem.error_code);
}
const { data, freshness, capabilities } = await response.json();
// data.paid_fee_zat is null on any transaction with shielded inputs.
// data.status is one of: mined | pending | conflicting | invalidated |
// suppressed | not_found | unavailable.