New 0-conf infrastructure for Liquid and other Elements-based deployments is here.
As a Blockstream-operated service, it aggregates mempool visibility for Liquid transactions. Nodes across the network report when they have seen a transaction, and this service exposes that data. As an integrator, you can use it as one input when deciding whether to accept a zero-confirmation payment, particularly in swap and other low-latency settlement flows.
The 0-conf service exists to make that signal available in a standard, queryable form. Instead of building bespoke federation monitoring, you can ask one service how widely a transaction has been observed across configured network tiers.
We are especially grateful to members of the Liquid Federation for their partnership during the beta phases. Their swap workloads, operational feedback, and testing helped validate the API design.
Why 0-Conf?
Liquid transactions are currently considered final once they are in a block that has one other block on top of it. In practice, that means waiting for two confirmations (two minutes) before treating a payment as settled on the Liquid Network.
Swap services, exchanges, and other applications that accept Liquid payments often need faster settlement times. Accepting transactions with zero confirmations reduces wait time, but it introduces double-spend risk.
This new 0-conf infrastructure helps integrators assess that risk. It’s a hosted API that reports how widely a given Liquid transaction has propagated across the network. It reports how widely a transaction has been observed across configured network observation tiers. Broad visibility is a useful signal for non-replace-by-fee (non-RBF) transactions, but it does not eliminate risk entirely.
For example, on Elements, if a transaction is not RBF-enabled, a node keeps the first conflicting spend of the same inputs it accepted. A subsequent transaction reusing those inputs is ignored, even with a higher fee. Under the assumption that federation members act honestly, wide mempool visibility for a non-RBF transaction suggests it is highly unlikely to be double-spent before confirmation.
Understanding Liquid’s Trust Model
As a federated sidechain, Liquid blocks are produced by a subset of members called functionary operators. For a payment that hasn’t opted into RBF, wide observation coverage is a strong signal that the network has converged on one version of the spend, so long as the federation members are acting honestly and their mempools are behaving normally.
0-conf doesn’t guarantee that a seen transaction will be confirmed. It merely tells you which observation nodes have reported seeing a given transaction in their mempool.
As a result, 0-conf gives you an accurate, real-time view of network mempool visibility. But while it’s a reliable basis for making an acceptance decision, visibility is still only an indicator, not a receipt for settlement purposes.
Observations in Practice
Each API response includes an observations object which maps observation tiers to counts of how many configured nodes in each tier have reported seeing the transaction.
Each tier reports:
- Seen: number of nodes in that tier that have reported the transaction
- Total: number of nodes configured for that tier
For example:
{
"txid": "<txid>",
"observations": {
"bridge": {
"seen": 1,
"total": 2,
},
"public": {
"seen": 0,
"total": 8,
},
"functionary": {
"seen": 12,
"total": 15,
}
}
}Note that the API doesn’t include a field indicating that a transaction is safe to accept without confirmation. Acceptance policy is application-defined.
Choosing REST or WebSocket
Both interfaces return the same observation data. The difference is how you receive updates.
REST
Best for simple, stateless checks: you have a txid and want the current observation counts right now.
- Straightforward to integrate from any HTTP client, cron job, or backend service
- No connection to maintain; each request is independent
- Easy to retry on failure
Tradeoffs:
- Observations change over time as more nodes see the transaction. REST only returns a snapshot at request time, so you must poll if you are waiting for coverage to increase
- Suited to "check once before accepting" or low-frequency status lookups, less ideal for watching propagation in real time
WebSocket
Best for latency-sensitive flows: you are waiting for observation counts to reach your threshold and want to act as soon as they do.
- Subscribe to a txid and receive a snapshot immediately, then further snapshot messages whenever observations change
- Multiple txids can be subscribed on a single connection
- Lower latency than polling; no repeated HTTP requests while you wait
Tradeoffs:
- Requires maintaining a persistent connection and handling disconnects, reconnects, and resubscription
- More client logic than a single REST call (subscribe, unsubscribe, parse message types, handle errors)
REST Interface
GET /api/v1/zeroconf/:txidReturns a JSON response with the transaction ID and current observations for that transaction:
{
"txid": "<txid>",
"observations": {
"bridge": {
"seen": 1,
"total": 2,
},
"public": {
"seen": 0,
"total": 8,
},
"functionary": {
"seen": 12,
"total": 15,
}
}
}WebSocket Interface
WS /ws/v1/zeroconfOpens a WebSocket connection. You then manage subscriptions over it by sending JSON messages: one to start watching a txid, one to stop.
Subscribe
{ "action": "subscribe", "txid": "<txid>" }Unsubscribe
{ "action": "unsubscribe", "txid": "<txid>" }You can maintain multiple simultaneous subscriptions on the same connection
Server messages
On successful subscription:
{
"action": "subscribed",
"txid": "<txid>",
"message": "subscription created"
}On snapshot or update (sent whenever observations change):
{
"action": "snapshot",
"txid": "<txid>",
"observations": {
"bridge": {
"seen": 1,
"total": 2,
},
"public": {
"seen": 0,
"total": 8,
},
"functionary": {
"seen": 12,
"total": 15,
}
}
}On expiration:
{
"action": "expired",
"txid": "<txid>",
"message": "subscription expired"
}On error:
{
"action": "error",
"reason": "bad_txid",
"message": "TXID must be 64 hex characters"
}Subscriptions expire automatically after a server-configured timeout, but you can re-subscribe if you still need updates.
Data Retention
The server periodically removes transactions from memory. Use this service to check recent mempool visibility, not as a long-term transaction index. Results may be incomplete or absent for transactions that have already been confirmed or have been in the mempool for an extended period.
Feedback and Bug Reports, Please!
If something looks wrong, or you have suggestions for improving the API or documentation, reach out through the Liquid Developer Telegram channel.
Please help us debug! Keep these details in mind when reporting them:
- The txid you queried (if applicable)
- Whether you used REST or WebSocket
- The request you sent and the response you received (including error messages)
- Approximate timestamp with timezone
- Your integration context (e.g., swap flow, merchant checkout) if relevant
To Learn More
- Check out the API reference
- Brush up on Liquid documentation
- Read about Liquid’s 2026 Roadmap
A version of this article was originally posted on the official Blockstream blog here: https://blog.blockstream.com/0-conf-for-elements-and-liquid-a-technical-explainer/