> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Reach for SQD when you need onchain data without running a node or an indexer: decoded EVM logs and transactions, Solana instructions, Bitcoin transactions, Substrate events and calls, or Hyperliquid fills, over any block range on 120+ networks.
> To query directly, POST to https://portal.sqd.dev/datasets/{dataset}/stream. The full API is described at https://docs.sqd.dev/openapi.json, and responses to the stream endpoints are JSON Lines.
> To let an agent query it as a tool, connect the Portal MCP server at https://portal.sqd.dev/mcp.
> Every page on this site is available as Markdown by appending .md to its URL.

# Bitcoin Portal API

> Stream Bitcoin blocks, transactions, inputs, and outputs through the SQD Portal API.

export function NetworksTable({networks, columns = {}, hideTestnetToggle = false}) {
  const {useState, useEffect} = React;
  const {showChainId = false, showTraces = false, showStateDiffs = false, showType = false, showCategory = false, showTier = true} = columns;
  const TIERS = ["Core", "Partner", "Frontier"];
  const [filter, setFilter] = useState("");
  const [copiedId, setCopiedId] = useState(null);
  const [sortColumn, setSortColumn] = useState("name");
  const [sortDirection, setSortDirection] = useState("asc");
  const [showTestnets, setShowTestnets] = useState(true);
  const [tierFilter, setTierFilter] = useState("all");
  useEffect(() => {
    const wanted = new URLSearchParams(window.location.search).get("tier");
    const match = TIERS.find(t => t.toLowerCase() === (wanted || "").toLowerCase());
    if (match) setTierFilter(match);
  }, []);
  const changeTierFilter = value => {
    setTierFilter(value);
    const url = new URL(window.location.href);
    if (value === "all") url.searchParams.delete("tier"); else url.searchParams.set("tier", value.toLowerCase());
    window.history.replaceState(null, "", url);
  };
  const filteredNetworks = networks.filter(network => {
    const networkType = network.type || (network.name.toLowerCase().includes("testnet") || network.name.toLowerCase().includes("devnet") ? "testnet" : "mainnet");
    if (!showTestnets && (networkType === "testnet" || networkType === "devnet")) {
      return false;
    }
    if (showTier && tierFilter !== "all" && network.tier !== tierFilter) {
      return false;
    }
    const filterLower = filter.toLowerCase();
    const nameMatch = network.name.toLowerCase().includes(filterLower);
    if (showChainId) {
      const chainIdMatch = network.chainId ? network.chainId.toString().includes(filterLower) : false;
      return nameMatch || chainIdMatch;
    }
    return nameMatch;
  });
  const hasStrictChainIdMatch = showChainId && filter.trim() !== "" && (/^\d+$/).test(filter.trim()) && filteredNetworks.some(network => network.chainId && network.chainId.toString() === filter.trim());
  const finalFilteredNetworks = hasStrictChainIdMatch ? filteredNetworks.filter(network => network.chainId && network.chainId.toString() === filter.trim()) : filteredNetworks;
  const handleSort = column => {
    if (sortColumn === column) {
      setSortDirection(sortDirection === "asc" ? "desc" : "asc");
    } else {
      setSortColumn(column);
      setSortDirection("asc");
    }
  };
  const sortedNetworks = [...finalFilteredNetworks].sort((a, b) => {
    let aVal, bVal;
    switch (sortColumn) {
      case "name":
        aVal = a.name.toLowerCase();
        bVal = b.name.toLowerCase();
        break;
      case "chainId":
        aVal = a.chainId ? parseInt(a.chainId) : 0;
        bVal = b.chainId ? parseInt(b.chainId) : 0;
        break;
      case "slug":
        aVal = a.slug.toLowerCase();
        bVal = b.slug.toLowerCase();
        break;
      case "portal":
        aVal = a.portal ? 1 : 0;
        bVal = b.portal ? 1 : 0;
        break;
      case "realtime":
        aVal = a.realtime ? 1 : 0;
        bVal = b.realtime ? 1 : 0;
        break;
      case "traces":
        aVal = a.traces ? 1 : 0;
        bVal = b.traces ? 1 : 0;
        break;
      case "stateDiffs":
        aVal = a.stateDiffs ? 1 : 0;
        bVal = b.stateDiffs ? 1 : 0;
        break;
      case "type":
        aVal = a.type || "";
        bVal = b.type || "";
        break;
      case "category":
        aVal = a.category || "";
        bVal = b.category || "";
        break;
      case "tier":
        aVal = TIERS.indexOf(a.tier) === -1 ? TIERS.length : TIERS.indexOf(a.tier);
        bVal = TIERS.indexOf(b.tier) === -1 ? TIERS.length : TIERS.indexOf(b.tier);
        break;
      default:
        return 0;
    }
    if (aVal < bVal) return sortDirection === "asc" ? -1 : 1;
    if (aVal > bVal) return sortDirection === "asc" ? 1 : -1;
    return 0;
  });
  const copyToClipboard = async (text, id) => {
    try {
      await navigator.clipboard.writeText(text);
      setCopiedId(id);
      setTimeout(() => setCopiedId(null), 2000);
    } catch (err) {
      console.error('Failed to copy:', err);
    }
  };
  const getPortalUrl = slug => `https://portal.sqd.dev/datasets/${slug}`;
  const getV2ArchiveUrl = slug => `v2.archive.subsquid.io/network/${slug}`;
  const colSpan = 4 + (showChainId ? 1 : 0) + (showTraces ? 1 : 0) + (showStateDiffs ? 1 : 0) + (showType ? 1 : 0) + (showCategory ? 1 : 0) + (showTier ? 1 : 0);
  return <div className="not-prose">
  <div className="sqd-nt-frame">
    <div className="sqd-nt-toolbar px-4 py-3 flex flex-wrap items-center gap-2">
        <input type="text" placeholder={showChainId ? "Filter by network name or chain ID..." : "Filter by network name..."} value={filter} onChange={e => setFilter(e.target.value)} className="sqd-nt-control sqd-nt-filter h-10 px-3" />
      {(!hideTestnetToggle || showTier) && <div className="sqd-nt-actions flex flex-wrap items-center gap-2">
        {!hideTestnetToggle && <button onClick={() => setShowTestnets(!showTestnets)} className={`sqd-nt-control inline-flex items-center h-10 gap-2 px-3 whitespace-nowrap ${showTestnets ? "" : "sqd-nt-toggle-off"}`} aria-pressed={showTestnets}>
            {showTestnets ? <svg className="w-4 h-4 sqd-nt-ok" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
              </svg> : <svg className="w-4 h-4 sqd-nt-dim" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
              </svg>}
            Show testnets
          </button>}
        {showTier && <select value={tierFilter} onChange={e => changeTierFilter(e.target.value)} className="sqd-nt-control sqd-nt-select h-10 pl-3 pr-8" aria-label="Filter by pricing tier">
            <option value="all">All tiers</option>
            {TIERS.map(t => <option key={t} value={t}>{t}</option>)}
          </select>}
      </div>}
    </div>
    <div className="sqd-nt-scroll">
      <table className="sqd-nt-table min-w-full border-collapse text-sm m-0">
        <thead>
          <tr>
            <th className="text-left py-3 pl-4 pr-3 cursor-pointer select-none" onClick={() => handleSort("name")}>
              <div className="flex items-center gap-1">
                Network
                {sortColumn === "name" && <span className="sqd-nt-dim">
                    {sortDirection === "asc" ? "↑" : "↓"}
                  </span>}
              </div>
            </th>
            {showChainId && <th className="text-left py-3 px-3 cursor-pointer select-none" style={{
    width: '100px',
    minWidth: '100px',
    maxWidth: '100px'
  }} onClick={() => handleSort("chainId")}>
                <div className="flex items-center gap-1">
                  Chain ID
                  {sortColumn === "chainId" && <span className="text-gray-500 dark:text-gray-400">
                      {sortDirection === "asc" ? "↑" : "↓"}
                    </span>}
                </div>
              </th>}
            {showType && <th className="text-left py-3 px-3 cursor-pointer select-none" style={{
    width: '90px',
    minWidth: '90px',
    maxWidth: '90px'
  }} onClick={() => handleSort("type")}>
                <div className="flex items-center gap-1">
                  Type
                  {sortColumn === "type" && <span className="text-gray-500 dark:text-gray-400">
                      {sortDirection === "asc" ? "↑" : "↓"}
                    </span>}
                </div>
              </th>}
            {showCategory && <th className="text-left py-3 px-3 cursor-pointer select-none" style={{
    width: '90px',
    minWidth: '90px',
    maxWidth: '90px'
  }} onClick={() => handleSort("category")}>
                <div className="flex items-center gap-1">
                  VM
                  {sortColumn === "category" && <span className="text-gray-500 dark:text-gray-400">
                      {sortDirection === "asc" ? "↑" : "↓"}
                    </span>}
                </div>
              </th>}
            {showTier && <th className="text-left py-3 px-3 cursor-pointer select-none" style={{
    width: '100px',
    minWidth: '100px',
    maxWidth: '100px'
  }} onClick={() => handleSort("tier")}>
                <div className="flex items-center gap-1">
                  <Tooltip tip="Pricing tier. Sets the price of adding this chain on the Growth plan.">
                    Tier
                  </Tooltip>
                  {sortColumn === "tier" && <span className="sqd-nt-dim">
                      {sortDirection === "asc" ? "↑" : "↓"}
                    </span>}
                </div>
              </th>}
            <th className="text-center py-3 px-2 cursor-pointer select-none" style={{
    width: '75px',
    minWidth: '75px',
    maxWidth: '75px'
  }} onClick={() => handleSort("portal")}>
              <div className="flex items-center justify-center gap-1">
                <Tooltip tip="Available on Portal infrastructure">
                  Portal
                </Tooltip>
                {sortColumn === "portal" && <span className="sqd-nt-dim">
                    {sortDirection === "asc" ? "↑" : "↓"}
                  </span>}
              </div>
            </th>
            <th className="text-center py-3 px-2 cursor-pointer select-none" style={{
    width: '75px',
    minWidth: '75px',
    maxWidth: '75px'
  }} onClick={() => handleSort("realtime")}>
              <div className="flex items-center justify-center gap-1 whitespace-nowrap">
                <Tooltip tip="Supports real-time streaming">Real-Time</Tooltip>
                {sortColumn === "realtime" && <span className="sqd-nt-dim">
                    {sortDirection === "asc" ? "↑" : "↓"}
                  </span>}
              </div>
            </th>
            {showTraces && <th className="text-center py-3 px-2 cursor-pointer select-none" style={{
    width: '75px',
    minWidth: '75px',
    maxWidth: '75px'
  }} onClick={() => handleSort("traces")}>
                <div className="flex items-center justify-center gap-1">
                  Traces
                  {sortColumn === "traces" && <span className="text-gray-500 dark:text-gray-400">
                      {sortDirection === "asc" ? "↑" : "↓"}
                    </span>}
                </div>
              </th>}
            {showStateDiffs && <th className="text-center py-3 px-2 cursor-pointer select-none" style={{
    width: '75px',
    minWidth: '75px',
    maxWidth: '75px'
  }} onClick={() => handleSort("stateDiffs")}>
                <div className="flex items-center justify-center gap-1 whitespace-nowrap">
                  State Diffs
                  {sortColumn === "stateDiffs" && <span className="text-gray-500 dark:text-gray-400">
                      {sortDirection === "asc" ? "↑" : "↓"}
                    </span>}
                </div>
              </th>}
            <th className="text-left py-3 px-3 cursor-pointer select-none" style={{
    width: '210px',
    minWidth: '210px'
  }} onClick={() => handleSort("slug")}>
              <div className="flex items-center gap-1">
                <Tooltip tip="Dataset identifier for use with Portal endpoints">
                  Slug
                </Tooltip>
                {sortColumn === "slug" && <span className="sqd-nt-dim">
                    {sortDirection === "asc" ? "↑" : "↓"}
                  </span>}
              </div>
            </th>
          </tr>
        </thead>
        <tbody>
          {sortedNetworks.length > 0 ? sortedNetworks.map((network, index) => {
    const portalId = `portal-${network.slug}`;
    const v2Id = `v2-${network.slug}`;
    return <tr key={index}>
                  <td className="network-name-cell sqd-nt-name py-3 pl-4 pr-3 text-left">
                    <span className="inline-flex items-center gap-2">
                      <span className={`sqd-nt-logo${network.logo ? "" : " sqd-nt-logo--mono"}${network.logoBg ? ` sqd-nt-logo--${network.logoBg}` : ""}`} aria-hidden="true">
                        {network.logo ? <img src={network.logo} alt="" width="20" height="20" loading="lazy" decoding="async" /> : network.name.charAt(0)}
                      </span>
                      {(() => {
      const name = network.details ? <a href={network.details} className="sqd-nt-name-link">
                            {network.name}
                          </a> : network.name;
      return network.tooltip ? <span className="inline">
                            <Tooltip tip={network.tooltip}>{name}</Tooltip>
                          </span> : name;
    })()}
                      {network.private && <span className="sqd-nt-badge">Private</span>}
                      {network.retiring && <Tooltip tip={"Retires " + network.retiring.at}>
                          <a href={network.retiring.href} className="sqd-nt-badge sqd-nt-badge--retiring">
                            Retiring {network.retiring.label}
                          </a>
                        </Tooltip>}
                    </span>
                  </td>
                  {showChainId && <td className="sqd-nt-cell py-3 px-3 text-left" style={{
      width: '90px',
      minWidth: '90px',
      maxWidth: '90px'
    }}>
                      {network.chainId || "-"}
                    </td>}
                  {showType && <td className="sqd-nt-cell py-3 px-3 text-left" style={{
      width: '90px',
      minWidth: '90px',
      maxWidth: '90px'
    }}>
                      <span className="sqd-nt-badge">
                        {network.type || "mainnet"}
                      </span>
                    </td>}
                  {showCategory && <td className="sqd-nt-cell py-3 px-3 text-left" style={{
      width: '90px',
      minWidth: '90px',
      maxWidth: '90px'
    }}>
                      <span className="sqd-nt-badge sqd-nt-badge--vm">
                        {network.category || "-"}
                      </span>
                    </td>}
                  {showTier && <td className="sqd-nt-cell py-3 px-3 text-left" style={{
      width: '100px',
      minWidth: '100px',
      maxWidth: '100px'
    }}>
                      {network.tier ? <a href="/en/portal/pricing#chain-tiers" className={`sqd-nt-badge sqd-nt-badge--tier sqd-nt-badge--${network.tier.toLowerCase()}`}>
                          {network.tier}
                        </a> : <span className="sqd-nt-no select-none text-base">–</span>}
                    </td>}
                  <td className="py-3 px-2 text-center" style={{
      width: '75px',
      minWidth: '75px',
      maxWidth: '75px'
    }}>
                    {network.portal ? <span className="sqd-nt-dot" /> : <span className="sqd-nt-no select-none text-base">–</span>}
                  </td>
                  <td className="py-3 px-2 text-center" style={{
      width: '75px',
      minWidth: '75px',
      maxWidth: '75px'
    }}>
                    {network.realtime ? <span className="sqd-nt-dot" /> : <span className="sqd-nt-no select-none text-base">–</span>}
                  </td>
                  {showTraces && <td className="py-3 px-2 text-center" style={{
      width: '75px',
      minWidth: '75px',
      maxWidth: '75px'
    }}>
                      {network.traces == null ? <Tooltip tip="Not applicable for this network type">
                          <span className="sqd-nt-no select-none text-base">–</span>
                        </Tooltip> : network.traces ? <span className="sqd-nt-dot" /> : <span className="sqd-nt-no select-none text-base">–</span>}
                    </td>}
                  {showStateDiffs && <td className="py-3 px-2 text-center" style={{
      width: '75px',
      minWidth: '75px',
      maxWidth: '75px'
    }}>
                      {network.stateDiffs == null ? <Tooltip tip="Not applicable for this network type">
                          <span className="sqd-nt-no select-none text-base">–</span>
                        </Tooltip> : network.stateDiffs ? <span className="sqd-nt-dot" /> : <span className="sqd-nt-no select-none text-base">–</span>}
                    </td>}
                  <td className="py-3 px-3 text-left">
                    <div className="flex items-center gap-2">
                      <code className="sqd-nt-chip">
                        {network.slug}
                      </code>
                      {network.portal && !network.private && <Tooltip tip={copiedId === portalId ? "Copied!" : "Copy Portal endpoint URL"}>
                          <button onClick={e => {
      e.stopPropagation();
      copyToClipboard(getPortalUrl(network.slug), portalId);
    }} className="sqd-nt-copy flex items-center justify-center" aria-label="Copy Portal URL">
                            <span className={copiedId === portalId ? "sqd-nt-ok" : ""}>
                              {copiedId === portalId ? <Icon icon="circle-check" iconType="solid" /> : <Icon icon="copy" iconType="regular" />}
                            </span>
                          </button>
                        </Tooltip>}
                    </div>
                  </td>
                </tr>;
  }) : <tr>
              <td colSpan={colSpan} className="sqd-nt-dim py-6 px-4 text-center">
                <div className="flex flex-col items-center gap-1.5">
                  <span className="text-lg">🔍</span>
                  <span>
                    {filter.trim() ? 'No networks found matching "' + filter + '"' : "No networks match these filters"}
                  </span>
                </div>
              </td>
            </tr>}
        </tbody>
      </table>
    </div>
  </div>
</div>;
}

export const bitcoinNetworks = [{
  "name": "Bitcoin",
  "logo": "https://cdn.subsquid.io/img/networks/bitcoin.svg",
  "type": "mainnet",
  "tooltip": "Full UTXO history: blocks, transactions, inputs (with prevout data), and outputs.",
  "portal": true,
  "realtime": true,
  "tier": "Core",
  "slug": "bitcoin-mainnet",
  "details": "/en/data/bitcoin/bitcoin-mainnet",
  "legacyUrl": null,
  "retiring": null
}];

Portal provides direct access to Bitcoin block and transaction data. Query blocks, transactions, inputs, and outputs with comprehensive filtering to analyze on-chain activity, track addresses, and monitor the Bitcoin network.

## Supported Networks

<Tip>
  Want the full list of every dataset we support? See [All Networks](/en/data/all-networks).
</Tip>

{(() => {
const { useState } = React;
return (
<NetworksTable
networks={bitcoinNetworks}
columns={{ showType: true }}
hideTestnetToggle={true}
/>
); })()}

## Next Steps

<CardGroup cols={2}>
  <Card title="Interactive Examples" icon="play" href="/en/portal/bitcoin/examples/query-transactions">
    Try live queries with our interactive examples
  </Card>

  <Card title="OpenAPI Schema" icon="file-code" href="https://docs.sqd.dev/en/api/catalog/bitcoin/openapi.yaml">
    Download the full OpenAPI specification
  </Card>
</CardGroup>

<Info>
  **Enterprise Custom Development**

  For enterprise clients requiring custom indexer development, please contact our team to discuss your specific requirements. [Schedule a Consultation →](https://calendly.com/t-tyrie-subsquid/30min)
</Info>


## Related topics

- [Bitcoin OpenAPI Schema](/en/ai/bitcoin-openapi.md)
- [Changelog](/changelog.md)
- [Bitcoin portal stream](/en/sdk/pipes-sdk/bitcoin/reference/basic-components/source.md)
- [Portal API introduction](/en/portal/introduction/portal-api.md)
- [Bitcoin](/en/data/bitcoin/bitcoin-mainnet.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.