https://nexus.gerowallet.io (Maestro’s Bitcoin services sit under
https://xbt-mainnet.gomaestro-api.org/v0, with the Node RPC service at /v0/rpc), and the
credential becomes an X-Api-Key: nxs_... header carrying a BITCOIN_MAINNET key. See
Authentication for how keys are issued and scoped.
Nexus keys are bound to one chain and one network at creation time. A Bitcoin key is created as
BITCOIN_MAINNET or BITCOIN_TESTNET4, the network query parameter is then optional, and
sending a value that disagrees with the key returns 400 Network Mismatch. If you also read
Cardano, that is a separate key on the same account, not a separate integration. See
Migrate from Maestro: Cardano for that half.Endpoint map
Maestro paths are shown relative to their/v0 base, so /rpc/... is the Node RPC service and the
bare paths are the Blockchain Indexer and Mempool Monitoring services.
Beyond the map, Nexus serves a bare inscription-and-rune summary at
GET /api/btc/addresses/{address}/ordinals, plus blocks, chain tip, fee estimates, mempool state
and direct ordinals lookups. See the API Reference for that surface.
Differences that are not drop-in
Ten behavioural notes, listed exhaustively. Everything else in the map is a path-and-header change.1. The watermark field is renamed
last_updated.block_height becomes tip.blockHeight. The value is fetched before the data
query, so it is never ahead of the rows you were handed. That makes it a safe scan watermark: on
the next poll you may re-scan a block, and you can never skip one. tip.blockHash is alongside it
for reorg detection.
2. BTC versus satoshi denominations
Transaction-level monetary values (vout[].value, vin[].prevout.value, fee) are BTC decimals,
where Maestro returned satoshi strings. UTXO value on the address endpoints stays in satoshis.
Two denominations, split by resource, so check every arithmetic site rather than applying one global
conversion.
3. Ordinals results carry an authority marker
Each UTXO returned withincludeOrdinals=true carries ordinalsIndexed. When it is true, the
inscriptions and runes fields are authoritative and an empty list means provably none. When it
is false, ord has not examined that output yet (typically an unconfirmed output, or ord lagging
the tip) and both fields are omitted rather than reported empty.
Match assets only on ordinalsIndexed=true entries. Treating an omitted field as “no inscriptions”
will misclassify outputs that simply have not been indexed yet; they resolve on confirmation.
4. runeId is best-effort
On the rare failure to resolve a rune name, runeId is null for that one balance rather than
failing the whole request. Tolerate the null and retry on the next poll instead of treating it as a
hard error.
5. Per-UTXO ordinals field shapes changed
runes[].runeId replaces rune_id, and inscriptions is a flat array of inscription ID strings
where Maestro returned objects keyed by inscription_id.
6. Inscription listing fields are satpoint-parsed
OnGET /api/btc/addresses/{a}/inscriptions, the fields satOffset, vout and txid replace
utxo_sat_offset, utxo_vout and utxo_txid. They are parsed out of the satpoint, which is also
returned verbatim. utxo_block_height and utxo_confirmations have no equivalent.
7. The mempool endpoint call can be deleted
GET /mempool/addresses/{a}/utxos has no Nexus counterpart because it does not need one:
unconfirmed UTXOs are always present in the main UTXO response with status.confirmed=false. Delete
the second call and filter client-side.
8. Mempool transactions have no prevout
A transaction fetched throughGET /api/btc/txs/{txid} while it is still in the mempool returns
inputs without prevout. That is a bitcoind limitation (no undo data exists until the transaction
is in a block), not a Nexus choice. Any logic that identifies a counterparty from input addresses
has to run against confirmed transactions.
9. Duplicates are possible during a paged scan
If a UTXO confirms partway through a paged scan it can appear twice, once unconfirmed and once confirmed. Key your upserts by(txid, vout) and the duplicate collapses.
10. Paged reads live on a separate route
The envelope comes fromGET /api/btc/addresses/{a}/utxos/page. Its sibling
GET /api/btc/addresses/{a}/utxos accepts only network and always returns the bare array, and
sending from, to, cursor, limit or includeOrdinals to it returns 400 with a message
naming the parameters it received and pointing at /utxos/page. The failure is deliberate:
ignoring them would answer a paged request with the entire unpaged set.
On /utxos/page, passing includeOrdinals=false is exactly equivalent to omitting the parameter.
It does not change the response shape, which is the envelope either way.
Worked examples
A UTXO page with ordinals, and a batch transaction lookup.null because the second txid is unknown. Order always mirrors the request,
so index alignment is safe.
Note the two denominations in one response: the UTXO
value above is 546 satoshis, while the
transaction vout[].value is 0.00000546 BTC. That is difference 2 in practice.Why not the free one
For Bitcoin there is no Koios. The no-cost options a Maestro user weighs are a self-hostedbitcoind plus an indexer such as electrs or ord, or the public mempool.space and blockstream.info
APIs, which publish no rate-limit guarantees and are run as a public good. Self-hosting gives full
control and costs an engineer’s time to keep an ord index in sync; the public APIs cost nothing and
promise nothing. Nexus serves address UTxOs, ordinals, runes, fees, mempool and submit behind one
key with per-tier rate limits and the same account that covers Cardano and Midnight. If your
Bitcoin reads are light and you can tolerate an unannounced limit, the public APIs are a fine
answer; if they are production traffic, they are not.
What to test first
Three checks that cover the differences most likely to bite.- A tip watermark round trip. Read a page from
/utxos/page, storetip.blockHeight, then poll again withfromset to the stored value. Confirm you see overlap rather than a gap, and that your upserts are keyed by(txid, vout)so a UTXO that confirmed between the two reads collapses instead of duplicating. - A batch call containing one fake txid. Send
POST /api/btc/txs/batchwith a real txid and 64 hex zeros, and confirm your deserializer accepts anullentry indatawithout throwing and without shifting subsequent indices. includeOrdinals=trueon a rune-holding address. Confirm you readruneIdinblock:txform, divideamountby10^divisibility, and skip any UTXO whoseordinalsIndexedisfalseinstead of recording it as holding nothing. Include an address with unconfirmed inbound funds so at least one such UTXO appears.
Next steps
Migrate from Maestro: Cardano
The Cardano half of the same migration
Authentication
Key creation, scoping, and the
network parameterRate Limits
Per-tier quotas and per-second limits
API Reference
The full Bitcoin surface, endpoint by endpoint