Issue Nº 29 — Sep 12, 2026
The mempool.space API splits across two backends, and each one fails differently
Issue twenty-nine covers mempool.space, the free Bitcoin block explorer and fee API. It needs no key. This session queried it live. Two separate backends sit behind one /api prefix, a bad address returns a different error shape than a bad transaction ID, and an address with zero history still returns 200, not an error.
One /api prefix, two backends, two error styles
GET /api/v1/fees/recommended, queried live this session, returned 200 with an x-powered-by header of Express. GET /api/blocks/tip/height, queried live this session, also returned 200, but its x-powered-by header read mempool-electrs 3.4.0-dev-bf622e5. Two different servers answer the same /api prefix.
The split follows a simple rule. Paths under /api/v1/ go to the Express backend, the mempool.space application itself. Paths without that prefix, such as /api/tx, /api/address, and /api/block, go to a bundled electrs fork, the Bitcoin indexer.
The two backends also disagree on response format. /api/blocks/tip/height, an electrs endpoint, returned the plain number 966502 as text/plain, even on a 200. /api/v1/fees/recommended, an Express endpoint, returned JSON. A client that always parses the body as JSON breaks on the electrs endpoints.
A malformed address and a missing transaction fail differently
GET /api/address/notarealaddress, queried live this session, returned 400 with a text/plain body reading Invalid Bitcoin address. The address string fails format validation before the indexer even looks it up.
GET /api/tx/{all-zero txid}, queried live this session, returned 404 with a text/plain body reading Transaction not found. The zero txid has valid hex format, so the indexer accepts the request and only then reports no matching record.
GET /api/block-height/99999999, queried live this session, returned the same pattern: 404 with a text/plain body reading Block not found. A malformed input gets 400. A well-formed input with no match gets 404. A client that treats both status codes as one generic failure loses that distinction.
A valid but unused address returns 200, not an error
This session generated a random, syntactically valid Bitcoin address that has never appeared on the chain. GET /api/address/{that address}, queried live this session, returned 200 with a JSON body of all-zero counts: funded_txo_count and tx_count both read 0, in chain_stats and in mempool_stats.
That 200 response contrasts with the 400 for a malformed address string. The API treats a wallet with no history as a valid, empty answer, not an error.
A status-code check alone cannot tell an empty wallet from an active one; both return 200. Read tx_count in the body to tell them apart.
Mempool, by the numbers
Enforced (exceeding it returns HTTP 429); exact numeric threshold is not publicly disclosed, though a paid enterprise sponsorship raises it
- GET/blocks/tip/height
- GET/v1/fees/recommended
- GET/tx/{txid}