Mesh LogoMesh

Blockstream Bitcoin Provider

Fetch Bitcoin chain data and submit transactions via the public Blockstream Esplora API — no API key required.

Overview

Blockstream operates a public Esplora REST API for Bitcoin mainnet and testnet. BlockstreamBitcoinProvider wraps this API and implements IBitcoinProvider from @meshsdk/provider, making it a drop-in data source for BitcoinHeadlessWallet.

When to use Blockstream:

  • Development and prototyping — no account or API key required
  • Low-to-medium volume production applications
  • Testnet development before deploying to mainnet

For authenticated production access, use BlockstreamEnterpriseBitcoinProvider. Both providers share the same Esplora REST methods via an internal HTTP client.

Quick Start

npm install @meshsdk/provider @meshsdk/wallet
import { BlockstreamBitcoinProvider } from "@meshsdk/provider";
import { BitcoinHeadlessWallet } from "@meshsdk/wallet";

const provider = new BlockstreamBitcoinProvider("testnet"); // "mainnet" | "testnet"

const wallet = await BitcoinHeadlessWallet.fromMnemonic({
  network: "Testnet4",
  mnemonic: ["word1", "word2", "..."],
  provider,
});

const balance = await wallet.getBalance();
// { confirmed: "100000", unconfirmed: "0", total: "100000" }

Configuration Options

ParameterTypeRequiredDescription
network"mainnet" | "testnet"YesBitcoin network to connect to

The base URLs used internally:

NetworkBase URL
"mainnet"https://blockstream.info/api
"testnet"https://blockstream.info/testnet/api

API Reference

fetchAddressInfo

Retrieve chain and mempool statistics for a Bitcoin address.

await provider.fetchAddressInfo(address: string): Promise<BitcoinAddressInfo>
ParameterTypeRequiredDescription
addressstringYesBitcoin address (bech32, P2PKH, P2SH, etc.)

Returns: BitcoinAddressInfo — confirmed and mempool funding/spending counts and sums.

Example:

import { BlockstreamBitcoinProvider } from "@meshsdk/provider";

const provider = new BlockstreamBitcoinProvider("mainnet");

const info = await provider.fetchAddressInfo("bc1q...");

console.log(info.chain_stats.funded_txo_sum);   // total confirmed received (sats)
console.log(info.mempool_stats.funded_txo_sum); // unconfirmed incoming (sats)

Return shape:

{
  address: "bc1q...",
  chain_stats: {
    funded_txo_count: 5,
    funded_txo_sum: 500000,
    spent_txo_count: 3,
    spent_txo_sum: 300000,
    tx_count: 8
  },
  mempool_stats: {
    funded_txo_count: 1,
    funded_txo_sum: 50000,
    spent_txo_count: 0,
    spent_txo_sum: 0,
    tx_count: 1
  }
}

fetchAddressUTxOs

Retrieve all unspent outputs for a Bitcoin address.

await provider.fetchAddressUTxOs(address: string): Promise<BitcoinUTxO[]>
ParameterTypeRequiredDescription
addressstringYesBitcoin address to query

Returns: Array of BitcoinUTxO objects.

Example:

const utxos = await provider.fetchAddressUTxOs("bc1q...");

utxos.forEach((utxo) => {
  console.log(`${utxo.txid}:${utxo.vout} — ${utxo.value} sats`);
});

Return shape:

[
  {
    txid: "abc123...",
    vout: 0,
    value: 50000,
    status: {
      confirmed: true,
      block_height: 840000,
      block_hash: "00000000...",
      block_time: 1710000000
    }
  }
]

fetchUTxO

Retrieve specific unspent output(s) from a transaction. Filters out already-spent outputs by cross-referencing the outspends endpoint.

await provider.fetchUTxO(txid: string, vout?: number): Promise<BitcoinUTxO[]>
ParameterTypeRequiredDescription
txidstringYesTransaction ID (64-char hex)
voutnumberNoOutput index to filter to; omit to return all unspent outputs

Example:

// All unspent outputs from a transaction
const utxos = await provider.fetchUTxO("abc123...");

// A specific output (only returned if unspent)
const utxo = await provider.fetchUTxO("abc123...", 0);

fetchAddressTxs

Retrieve transaction history for a Bitcoin address. The provider returns the Esplora page unchanged: GET /address/{address}/txs, or GET /address/{address}/txs/chain/{lastSeenTxid} when a cursor is set. Esplora returns up to 25 transactions per page, unconfirmed first, then confirmed newest-first.

await provider.fetchAddressTxs(
  address: string,
  lastSeenTxid?: string,
): Promise<BitcoinTxInfo[]>
ParameterTypeRequiredDescription
addressstringYesBitcoin address to query
lastSeenTxidstringNoTxid of the last transaction seen; fetches the next page of results

Example:

// First Esplora page
const txs = await provider.fetchAddressTxs("bc1q...");

// Next page
const moreTxs = await provider.fetchAddressTxs("bc1q...", txs[txs.length - 1].txid);

Blockstream paginates using path-based cursors: /address/{address}/txs/chain/{lastSeenTxid}.


fetchTxInfo

Retrieve the confirmation status of a transaction.

await provider.fetchTxInfo(txid: string): Promise<BitcoinTxStatus>
ParameterTypeRequiredDescription
txidstringYesTransaction ID (64-char hex)

Returns: BitcoinTxStatus — confirmation status and block details.

Example:

const status = await provider.fetchTxInfo("abc123...");

if (status.confirmed) {
  console.log(`Confirmed at block ${status.block_height}`);
} else {
  console.log("Pending in mempool");
}

Return shape:

{
  confirmed: true,
  block_height: 840000,
  block_hash: "00000000...",
  block_time: 1710000000
}

fetchFeeEstimates

Retrieve the recommended fee rate (sat/vB) for a target confirmation within blocks blocks, from GET /fee-estimates. A failed request throws. If that block target is missing, the provider uses the smallest target greater than or equal to blocks, or the largest target in the map when every target is smaller. It returns 2 only when that lookup still has no rate.

await provider.fetchFeeEstimates(blocks: number): Promise<number>
ParameterTypeRequiredDescription
blocksnumberYesTarget confirmation speed in blocks (e.g. 1, 6, 144)

Example:

const feeRate = await provider.fetchFeeEstimates(6); // 6-block target
console.log(`Recommended: ${feeRate} sat/vB`);

fetchScriptInfo

Retrieve chain and mempool statistics for a script hash (P2SH / P2WSH).

await provider.fetchScriptInfo(hash: string): Promise<BitcoinScriptInfo>
ParameterTypeRequiredDescription
hashstringYesEsplora script hash. Passed through to /scripthash/{hash} with no hashing or byte reversal

fetchScriptUTxOs

Retrieve unspent outputs locked by a script hash.

await provider.fetchScriptUTxOs(hash: string): Promise<BitcoinUTxO[]>

fetchScriptTxs

Retrieve transaction history for a script hash, with optional pagination.

await provider.fetchScriptTxs(
  hash: string,
  lastSeenTxid?: string,
): Promise<BitcoinTxInfo[]>

submitTx

Broadcast a signed raw transaction to the Bitcoin network.

await provider.submitTx(txHex: string): Promise<string>
ParameterTypeRequiredDescription
txHexstringYesSigned raw transaction in hex format

Returns: The broadcast transaction ID (64-char hex).

Example:

const txid = await provider.submitTx(signedRawTxHex);
console.log(`Broadcast: ${txid}`);

Blockstream's /tx endpoint accepts text/plain and returns the txid as plain text on success.


Complete Example

import { BlockstreamBitcoinProvider } from "@meshsdk/provider";
import { BitcoinHeadlessWallet, AddressPurpose } from "@meshsdk/wallet";

async function sendBitcoin() {
  const provider = new BlockstreamBitcoinProvider("testnet");

  const wallet = await BitcoinHeadlessWallet.fromMnemonic({
    network: "Testnet4",
    mnemonic: ["your", "twelve", "word", "mnemonic", "phrase", "here", "..."],
    provider,
  });

  // Check balance
  const balance = await wallet.getBalance();
  console.log(`Balance: ${balance.total} sats`);

  // Get receive address
  const [address] = await wallet.getAddresses([AddressPurpose.Payment]);
  console.log(`Address: ${address.address}`);

  // Send to a recipient
  const txid = await wallet.signTransfer([
    { address: "tb1q...", amount: 10_000 }, // satoshis
  ]);
  console.log(`Sent: ${txid}`);
}

References

On this page