JSON-RPC Extensions
satd preserves Bitcoin Core's JSON-RPC contract by default: the same method
names, response field names, and types, so existing clients work unchanged.
On top of that, satd adds opt-in extensions for developers and integrators.
Each extension is either enabled by a server flag (and is therefore
live-reloadable over SIGHUP) or exposed as an additional method or
parameter. None of them alters the default Core-compatible wire shape. All
are governed by the
stability policy.
The authoritative catalogue of where satd differs from Core is
CORE_DIFFERENCES.md.
For the push-based event firehose and cursor-resumable watch subscriptions (gRPC, WebSocket, SSE, ZMQ), see the Streaming Consumption API chapter. That is a distinct surface from the extensions described here.
Note. JSON-RPC keeps Bitcoin Core's cookie /
rpcuser/rpcauthcredentials by default. Capability-scoped bearer tokens (-rpcauthbearer,rpc:read/rpc:write) are an opt-in addition. See Authentication & Authorization.
Satoshis-as-integers
Bitcoin Core emits every amount as an IEEE-754 double in whole BTC
(0.00001000), which loses precision near dust and at the supply boundary.
This is Core's long-standing
#3249, open since 2013.
satd can instead emit exact integer satoshis.
This is a server-wide default, --rpc-default-units=sats|btc
(rpcdefaultunits as a config key), not a per-request flag. The default is
btc, where output is byte-identical to Core: a fixed 8-decimal number,
formatted from the integer satoshi value so it is exact. Set it to sats
and amounts serialize as JSON integers everywhere. In that mode responses
also carry a _units: "sats" tag so a client can confirm the shape it
received. The tag is absent in the default btc mode, which stays
byte-for-byte compatible. The option is live-reloadable. A per-request
HTTP-header override is a planned follow-up.
Structured RPC errors
By default, error responses are byte-identical to Core's {code, message}.
--rpc-extended-errors (rpcextendederrors; default off, live-reloadable)
is a server-wide option. With it enabled, satd additionally populates the
JSON-RPC data object with machine-actionable fields:
category: a stable taxonomy string, for examplemempool.policy.feerate,validation.consensus,storage.not_found.suggestion: a concrete remediation hint, when one applies.debug: arbitrary structured detail (field positions, computed values), when present.
Category names are stable once shipped in a release: new names can be
added, and existing ones never change meaning. As with the units default,
this is a server-wide option, since the common deployment pattern is satd
driven only by satd-aware tooling. A per-request X-Satd-Extended-Errors
header is a planned follow-up.
Fee estimation
Core's estimatesmartfee conf_target [estimate_mode] is kept with its
exact response shape ({feerate, blocks, errors}) and is Core-compatible
by default. The optional mode argument accepts Core's economical /
conservative / unset vocabulary, all treated as the historical
estimator. It also accepts satd's own historical / mempool / blend
values.
satd also adds an estimatefees [targets] [mode] method (default mode
blend, default targets [1, 3, 6, 12, 24]). It simulates the next N
block templates from the current mempool, with ancestor-feerate
(CPFP-aware) package sorting. It never hard-errors; it always returns a
result. The response maps each target to a {feerate, confidence} pair,
where confidence is high | medium | low, and includes a feerate
histogram. This is the basis for Core's
#11500.
Mempool subscription stream
subscribemempool is a JSON-RPC WebSocket subscription, paired with
unsubscribemempool, that emits structured lifecycle events. Each event is
tagged by a kind field:
enter: a transaction was admitted to the mempool.leave_confirmed: it was confirmed in a block.leave_evicted: it was dropped, with an explicitreason(full_pool|expiry).leave_replaced: it was RBF-replaced, carrying thereplacing_txid.
Bitcoin Core requires polling getrawmempool or rebuilding this state from
per-tx ZMQ frames. This stream carries explicit eviction reasons and RBF
replacement linkage directly. For the richer firehose with cursor replay,
see the Streaming Consumption API; subscribemempool is
the lightweight JSON-RPC option.
Silent-payment block data
getsilentpaymentblockdata "blockhash" ( verbosity dust_limit ) returns the
public BIP 352 tweak data for one block, from the tweak index
(-silentpaymentindex=1, default off). It is the JSON-RPC fallback for the
streaming tweaks category — the same bytes, for scripts, the
reference-implementation differential, and integrators not yet on an SDK.
verbosity 0(default) →{ "block_hash", "height", "tweaks": ["<33-byte hex>", …] }.verbosity 1→ each entry becomes{ "txid", "tweak", "max_value" }.dust_limit(sats, default0) drops entries whose largest taproot output value is below the floor.
Errors: -5 for an unknown or non-active block, -8 when the index is
disabled, and -1 when the block is not yet indexed at that height (the row is
absent — a height-by-height scanner cannot proceed past a gap, but unlike BIP
157 it cannot silently miss its own outputs either). The method is read-only. A
light client runs one ECDH per returned tweak locally, so the scan key never
reaches the node; for the streaming firehose with cursor replay, see the
Streaming Consumption API.
Client-side PSBT signing (no signing RPC)
There is no signing method: satd never handles private keys. Signing is a
client-side sat-cli command.
sat-cli signpsbtwithkey reads a WIF private key or a BIP-32 xpriv from
stdin, prompting without echo when stdin is a terminal. It signs the PSBT
entirely locally, using only the prevout data already carried in the PSBT.
It covers the common single-sig script types (Legacy, SegWit v0, nested
SegWit, and Taproot key-path) and writes partial_sigs / tap_key_sig for
the node's finalizepsbt to assemble, rather than finalizing itself. An
xpriv is expanded over the standard BIP 44/49/84/86 paths, so it can sign
PSBTs that carry no derivation metadata, including satd's own createpsbt
output. The key never crosses the JSON-RPC boundary, so satd stays strictly
keyless.