This document describes all available API endpoints for the Waterfalls server, which provides blockchain data indexing and querying capabilities for Bitcoin and Elements/Liquid networks.
These endpoints provide transaction history and UTXO data for descriptors or addresses. Available in both JSON and CBOR formats.
GET /v2/waterfalls?<query_params>
GET /v2/waterfalls.cbor?<query_params>
Note: v1 exists for compatibility and v3 endpoints have been removed and return 404.
Query Parameters:
-
descriptor(string): Bitcoin/Elements descriptor (plain text or encrypted with server key)- Cannot be used together with
addresses - Supports encryption using age encryption with server's public key
- Network validation: mainnet descriptors (xpub) cannot be used on testnet/regtest
- Cannot be used together with
-
addresses(string): Comma-separated list of Bitcoin/Elements addresses- Cannot be used together with
descriptor - Maximum addresses limited by server configuration
- Addresses cannot be blinded (confidential)
- Cannot be used together with
-
page(integer, optional): Page number for pagination (default: 0)- For
descriptor, this selects the derivation window - For
addresses, pagination is supported only when exactly one address is supplied - When more than one address is supplied,
pagemay be omitted or set to0 - Requests with more than one address and
page > 0return400
- For
-
to_index(integer, optional): Maximum derivation index for descriptors (default: 0) -
utxo_only(boolean, optional): Return only unspent outputs (default: false)- If any requested script has more history than the server-side truncation threshold, the request returns
400 UtxoOnlyHistoryTooLarge
- If any requested script has more history than the server-side truncation threshold, the request returns
History truncation:
- To avoid unbounded responses on highly reused addresses, Waterfalls caps the number of confirmed
TxSeenentries returned for a single script pubkey - The server-side cap is configurable with
--max-txs-seen(orMAX_TXS_SEEN) and defaults to100 - Truncation is applied independently to each script/address result
- For
addresses=<single_address>, clients can continue the confirmed history by increasingpage - Mempool entries are included on page
0; subsequent pages contain only confirmed history - Descriptor responses do not page the history of a single derived address; instead,
has_morelists the concrete derived addresses whose history was truncated so the client can continue via theaddressesendpoint - For descriptor-derived scripts that do not have an address representation (for example bare scripts),
has_morecontains a sentinel string of the formnon_address_script:<derivation_index>
Response Format (JSON):
{
"txs_seen": {
"descriptor_or_addresses": [
{
"txid": "transaction_id",
"height": 12345,
"block_hash": "block_hash",
"block_timestamp": 1234567890,
"v": 1
}
]
},
"has_more": [
"truncated_address_1"
],
"page": 0,
"tip": "current_tip_hash"
}Response fields:
txs_seen: Transaction history grouped by descriptor key or by the literal"addresses"keyhas_more(array of strings, optional): Usually concrete addresses whose confirmed history was truncated on this response page. For descriptor-derived scripts without an address form, entries use the sentinel formatnon_address_script:<derivation_index>page: Echoes the requested pagetip: Current tip block hash
Differences between v1 and v2:
- v2 includes
tipfield in response
GET /v4/waterfalls?<query_params>
GET /v4/waterfalls.cbor?<query_params>
The v4 endpoints accept the same query parameters as v2 but return extended tip metadata including block height. This is particularly useful for Bitcoin, where the block height cannot be derived from the header alone.
Response Format (JSON):
{
"txs_seen": {
"descriptor_or_addresses": [
{
"txid": "transaction_id",
"height": 12345,
"block_hash": "block_hash",
"block_timestamp": 1234567890,
"v": 1
}
]
},
"has_more": [
"truncated_address_1"
],
"page": 0,
"tip_meta": {
"b": "current_tip_block_hash",
"t": 1234567890,
"h": 876543
}
}Differences between v2 and v4:
- v4 returns
tip_metaobject instead oftiphash string tip_metacontains:b(string): Block hash of the current tipt(integer): Block timestamp (Unix epoch seconds)h(integer): Block height
- v2 and v4 both support history truncation and the optional
has_morefield
GET /v1/last_used_index?descriptor=<descriptor>
Returns the highest derivation index that has been used (has transaction history) for both external and internal chains. This is useful for quickly determining the next unused address without downloading full transaction history.
Query Parameters:
descriptor(string, required): Bitcoin/Elements descriptor (plain text or encrypted with server key)- Supports encryption using age encryption with server's public key
- Network validation: mainnet descriptors (xpub) cannot be used on testnet/regtest
Response Format (JSON):
{
"external": 42,
"internal": 15,
"tip": "current_tip_hash"
}Response Fields:
external(integer or null): Last used index on the external (receive) chain, or null if no addresses have been usedinternal(integer or null): Last used index on the internal (change) chain, or null if no addresses have been usedtip(string, optional): Current blockchain tip hash for reference
Use Case:
This endpoint is optimized for applications that only need to know the next unused address index (e.g., Point of Sale systems) without the overhead of downloading full transaction history or computing balances.
Example:
To get the next unused external address, use index external + 1 (or index 0 if external is null).
GET /v1/subscribe?descriptor=<descriptor>
Opens a Server-Sent Events (SSE) stream that notifies the client when a previously scanned descriptor may have new activity. The notification is only a hint; clients should perform the normal Waterfalls scan after receiving an event.
Query Parameters:
descriptor(string, required): Bitcoin/Elements descriptor (plain text or encrypted with server key)- Supports encryption using age encryption with server's public key
- Network validation: mainnet descriptors (xpub) cannot be used on testnet/regtest
- Must have a wildcard
Precondition:
- The descriptor must have been scanned with
/v1/waterfalls,/v2/waterfalls, or/v4/waterfallsbefore subscribing - If the descriptor has never been scanned, the server returns
400 DescriptorNotScanned - The server tracks the highest used derivation index observed during scans
- Subscriptions watch scripts up to
max_used_index + GAP_LIMIT; if a descriptor was scanned but has no used index yet, the initial gap window is watched
Response:
- Status:
200 OK - Content-Type:
text/event-stream - The stream starts with a comment event:
: ready
When an update is available, the server sends:
event: update
data: {"type":"mempool","tip":{"height":12345,"block_hash":"current_tip_hash","timestamp":1234567890}}
Event Data:
type(string): Event typetip(object, optional): Latest known chain tip when the event is sentheight(number): Tip block heightblock_hash(string): Tip block hashtimestamp(number): Tip block timestamp as Unix epoch seconds
Event Types:
tip: a new block was indexed, but no watched script changed for this subscriptionblock: a new block was indexed and a watched script changed for this subscriptionmempool: a watched script appeared in a newly observed mempool transactionreorg: a chain reorganization happened; clients should rescan because affected scripts are not filtered precisely
For each newly indexed block, each subscription receives either block or tip, not both. Mempool removals do not emit mempool events. In the common confirmation path, the server emits mempool when the transaction first appears and block after the confirming block is indexed.
Limitations:
- At the moment active subscriptions do not expand when later scans increase the descriptor's highest used index
- To watch the expanded range, clients should close the current SSE stream and re-open a new subscription
Client Behavior:
- Treat events as invalidation hints, not as wallet updates
- On any
updateevent, run the usual Waterfalls scan to obtain authoritative history and tip state - On reconnect, run a Waterfalls scan before relying on subscription events, because events may have been missed while disconnected
GET /v1/server_recipient
Returns the server's public key for encryption purposes.
Response: Plain text string containing the public key
GET /v1/server_address
Returns the server's Bitcoin/Elements address for message signing verification.
Response: Plain text string containing the address
GET /v1/time_since_last_block
Returns the time elapsed since the last block and a freshness indicator.
Response: Plain text describing time elapsed and status (e.g., "120 seconds since last block, less than 10 minutes")
GET /v1/build_info
Returns build and version information including git commit ID.
Response (JSON):
{
"version": "0.9.4",
"git_commit": "a1b2c3d4e5f6789..."
}GET /blocks/tip/hash
Returns the hash of the current blockchain tip.
Response: Plain text string containing the block hash
GET /block-height/{height}
Returns the block hash for a specific block height.
Parameters:
height(integer): Block height
Response: Plain text string containing the block hash, or 404 if not found
GET /block/{hash}/header
Returns the block header for a specific block hash.
Parameters:
hash(string): Block hash
Response: Hex-encoded block header, or 404 if not found
GET /tx/{txid}/raw
Returns the raw transaction data.
Parameters:
txid(string): Transaction ID
Response: Binary transaction data (application/octet-stream)
GET /address/{address}/txs
Returns transaction history for a specific address in Esplora-compatible format.
Parameters:
address(string): Bitcoin/Elements address
Notes:
- Confirmed history is capped by the same server-side truncation threshold used by the waterfalls endpoints
- This endpoint currently returns only the first capped page of confirmed history, plus current mempool entries
- If an address has more history than the cap, older confirmed transactions are not returned by this endpoint
Response (JSON):
[
{
"txid": "transaction_id",
"status": {
"block_height": 12345,
"block_hash": "block_hash_or_null"
}
}
]GET /fee-estimates
Returns fee estimates for various confirmation targets in sat/vB (satoshis per virtual byte). The endpoint queries either the connected node's RPC or proxies to Esplora depending on server configuration.
Response Format (JSON):
The following is a non-exhaustive example, more keys are present:
{
"1": 10.5,
"2": 8.2,
"3": 7.5,
"1008": 1.0
}Response Fields:
The response is a JSON object where:
- Key (string): Confirmation target in blocks (e.g., "1", "6", "144")
- Value (float): Estimated fee rate in sat/vB for that confirmation target
Confirmation Targets:
The endpoint provides estimates for the following confirmation targets (in blocks):
- Short-term: 1-25 blocks
- Medium-term: 144 blocks (~1 day)
- Long-term: 504 blocks (~3.5 days), 1008 blocks (~1 week)
Caching:
Fee estimates are cached server-side for 30 seconds to reduce load on the underlying node or Esplora API.
POST /tx
Broadcasts a raw transaction to the network.
Request Body: Raw transaction hex string
Response:
- Success (200): Transaction ID
- Error (400): Error message
GET /metrics
Returns Prometheus-formatted metrics for monitoring.
Response: Text format metrics (text/plain)
The API returns appropriate HTTP status codes:
200 OK: Successful request400 Bad Request: Invalid parameters or transaction broadcast failure404 Not Found: Resource not found (block, transaction, endpoint)422 Unprocessable Entity: Decryption failure (wrong identity used for encrypted descriptor)500 Internal Server Error: Server error
Common error conditions:
AtLeastOneFieldMandatory: Neither descriptor nor addresses providedCannotSpecifyBothDescriptorAndAddresses: Both descriptor and addresses providedWrongNetwork: Network mismatch (e.g., mainnet descriptor on testnet)TooManyAddresses: Exceeds maximum address limitAddressCannotBeBlinded: Blinded/confidential address providedAddressPageRequiresSingleAddress:page > 0was used with more than one addressUtxoOnlyHistoryTooLarge:utxo_only=truewas requested for a script whose history exceeds the truncation thresholdInvalidTxid: Malformed transaction IDInvalidBlockHash: Malformed block hashCannotFindTx: Transaction not foundCannotFindBlockHeader: Block header not found
The codebase includes a WaterfallClient class with the following methods:
// Query with descriptor (v2, JSON)
let (response, headers) = client.waterfalls(descriptor).await?;
// Query with addresses
let (response, headers) = client.waterfalls_addresses(&addresses).await?;
// Version-specific queries
let (response, headers) = client.waterfalls_v1(descriptor).await?;
let (response, headers) = client.waterfalls_v2(descriptor).await?;
// UTXO-only query
let (response, headers) = client.waterfalls_v2_utxo_only(descriptor).await?;
// Generic version with all parameters
let (response, headers) = client.waterfalls_version(
descriptor,
version,
page,
to_index,
utxo_only
).await?;// Get current tip
let tip_hash = client.tip_hash().await?;
// Get block header
let header = client.header(block_hash).await?;
// Get transaction
let transaction = client.tx(txid).await?;
// Get address transactions
let txs_json = client.address_txs(&address).await?;// Get server public key
let recipient = client.server_recipient().await?;
// Get server address
let address = client.server_address().await?;// Broadcast transaction
let txid = client.broadcast(&transaction).await?;-
Message Signing: Responses include cryptographic signatures in headers:
X-Content-Signature: Message signatureX-Content-Digest: Content digestX-Server-Address: Server address for verification
-
Encryption Support: Descriptors can be encrypted using age encryption with the server's public key
-
CORS Support: Configurable CORS headers for web client access
- Responses include appropriate cache control headers
- Address and transaction endpoints have long cache times for confirmed data
- Mempool/tip data has shorter cache times or no caching