REST API Documentation
Base URL: /api/v1
The API is anonymous by default — no authentication is required for read endpoints. Optionally send an API key to raise your rate limit. CORS is open. All JSON responses are UTF-8.
Rate Limits
Per-IP request limits are enforced per surface. Static assets, /health, /favicon.ico, /robots.txt, and /sitemap.xml are exempt.
- API (
/api/v1/*, incl. the WhatsonChain-compatible mirror): 240 requests per minute per IP. - Interactive site (HTML pages and HTMX partials): 900 requests per minute per IP. A single page view fans out into several requests, so this surface has a higher limit than the API.
- Transaction broadcast (
POST /tx/broadcast,POST /tx/broadcast/multi): a separate, stricter cap of 10 per minute per IP, layered on top of the API limit because these routes proxy to external ARC infrastructure.
Successful responses include:
X-RateLimit-Limit: requests allowed per window.X-RateLimit-Remaining: requests left in the current window.
When you exceed the limit you get HTTP 429 Too Many Requests with body {"error": "rate limit exceeded"}. Wait at least one minute and retry.
Requests carrying a valid API key are metered against their key's tier instead of the per-IP bucket.
Authentication
Authentication is optional. Anonymous requests work within the per-IP limits above; supplying an API key meters your requests against your key's tier and raises your ceiling. Send the key one of two ways:
Authorization: Bearer <key>X-API-Key: <key>
Keys look like bb_live_… (mainnet) or bb_test_… (testnet) and are issued by the operator. An invalid or revoked key returns HTTP 401; omit the header to fall back to anonymous access. Keyed responses include an X-API-Tier header. Tier limits (for this deployment):
| Tier | Requests per minute |
|---|---|
| Anonymous (per IP) | 240 |
free | 600 |
pro | 3000 |
enterprise | 12000 |
/key/usageReturns the calling key's tier, per-minute limit, and today's request total. Requires a key (401 otherwise). Response: {"key_prefix", "tier", "limit_per_min", "used_today", "reset_at"}.
Try it
Send a live request to this API from your browser. Anonymous requests work within the per-IP limits; paste an API key to use your tier's higher limit. The key is used only by your browser for these requests and is never sent anywhere else.
Pagination
Pagination conventions vary by endpoint depending on the underlying data shape. Cursor-style endpoints page through ordered series (blocks, address transactions); offset-style endpoints page through indexed snapshots (rich list, token holders). Where both are offered on the same resource, the cursor form is preferred for deep pages.
| Endpoint | Style | Parameters | Default / Max |
|---|---|---|---|
/blocks | Cursor | from, limit | 20 / 100 |
/address/<addr>/txs | Cursor | from_height, limit | 20 / 100 |
/address/<addr>/utxos | Offset (legacy) or Cursor | page, limit, sort, or cursor | 20 / 100; page capped at 50 |
/stats/richlist | Offset | page, limit, sort, dir | 20 / 100 |
/tokens | Offset | page, limit, sort, dir | 20 / 100 |
/token/<id>/holders | Offset | page, limit | 20 / 100 |
/token/<id>/history | Offset | page, limit | 20 / 100 |
Cursor endpoints page backwards through the chain (for blocks/txs the natural order is newest→oldest). Pass the last item's key (a height) as from / from_height to fetch the next page. Offset endpoints use zero-indexed page.
Blocks
/block/tipReturns the current chain tip block.
/block/latestReturns the latest block (alias for tip).
/block/<id>Returns a block by height or hash.
/block/<id>/protocolsReturns the protocol tag distribution for a block. Response: array of {"protocol", "name", "short", "color", "tx_count"} covering detected on-chain protocols (ORD, BSV21, MAP, B, etc.) within the block.
/blocks?from=&limit=Returns a paginated list of blocks. Cursor-style: from is the upper-bound height (exclusive when paging back), limit defaults to 20, max 100.
/block/header/height/<height>/rawReturns the raw 80-byte block header as binary (application/octet-stream) for a given height. Use /block/headers/latest for a hex-encoded variant.
/block/headers/latestReturns the 80-byte block header of the current chain tip as a hex string.
/block/headers/resourcesReturns JSON array of downloadable header chunk URLs (2016-block difficulty periods). Each entry has url and label fields.
/block/headers/<from>-<to>Downloads concatenated raw 80-byte headers for a height range as binary. Max 2016 blocks per request. Useful for SPV header chain sync.
/block/count?minerId=<miner>Returns the total number of blocks mined by a specific miner. Response: {"miner": "TAAL", "blocks": 12345}
Transactions
/tx/<txid>Returns a parsed transaction with inputs, outputs, and spend status.
/tx/<txid>/hexReturns the raw transaction as a hex string.
/tx/<txid>/binReturns the raw transaction as binary.
/tx/<txid>/proofReturns the merkle proof for a transaction.
/tx/<txid>/inscription/<vout>Returns the inscription content embedded in the specified output. Served with the original MIME type (e.g. image/png, text/html). Returns 404 if no inscription exists at that output.
/tx/<txid>/nft/<vout>Renders the NFT at the specified output, resolving the seed-inscription chain (re-inscriptions follow the prior tx's inscription content). Served with the original MIME type. Returns 404 if no inscription is reachable from that output.
/tx/<txid>/bfile/<vout>Returns the B:// file content embedded in the specified output. Served with the original MIME type. Returns 404 if no B:// data exists at that output.
/tx/<txid>/media/<vout>Returns embedded media from the output, auto-detecting the format (inscription, B://, or other on-chain media). Served with the detected MIME type. Returns 404 if no media is found.
/tx/<txid>/beefReturns a BRC-95 Atomic BEEF bundle (transaction + ancestor chain + merkle proofs) as binary. Used for SPV verification.
/tx/<txid>/beef/hexReturns a BRC-95 Atomic BEEF bundle as a hex string.
/tx/<txid>/statusReturns the confirmation status of a transaction.
/tx/<txid>/propagationReturns propagation status across BSV nodes — shows which nodes have seen the transaction and whether it is in mempool or confirmed.
/tx/<txid>/graphReturns the transaction ancestry graph — a tree of input transactions and their ancestors. Useful for visualizing transaction lineage.
/tx/broadcastBroadcasts a raw transaction. Body: {"rawtx": "hex"}
/tx/broadcast/multiBroadcasts multiple raw transactions. Body: array of hex strings.
Addresses
/address/<addr>Returns address info with balance and UTXO count.
/address/<addr>/txs?page=Returns paginated transaction history for an address.
/address/<addr>/utxos?page=Returns paginated UTXOs for an address.
/address/<addr>/balanceReturns just the balance for an address.
/address/<addr>/scriptsReturns the locking scripts associated with an address.
/address/<addr>/tokensReturns BSV-21 token holdings for an address.
/address/<addr>/token/<tokenId>/historyReturns token transfer history for a specific token at an address.
TXO
/txo/<txid>/<vout>Returns a specific transaction output.
/txo/<txid>/<vout>/spendReturns the spending transaction for an output, if spent.
Downloads
/download/tx/<txid>Downloads the raw transaction as a binary file.
/download/tx/<txid>/hexDownloads the raw transaction as a hex text file.
/download/tx/<txid>/output/<index>Downloads a specific output script as binary.
/download/tx/<txid>/output/<index>/hexDownloads a specific output script as hex.
/download/tx/<txid>/input/<index>Downloads a specific input script as binary.
/download/tx/<txid>/input/<index>/hexDownloads a specific input script as hex.
/download/tx/<txid>/receiptDownloads a PDF receipt for a transaction.
/download/address/<addr>/statementDownloads a PDF statement of recent transactions for an address.
Search
/search?q=Auto-detects query type (txid, block hash/height, address) and returns a redirect.
Stats
/stats/summaryReturns chain summary (height, hashrate, difficulty, price, market cap).
/stats/networkReturns daily network statistics (blocks, txs, fees, hashrate).
/stats/miningReturns mining pool distribution.
/stats/mining/histogram?period=<24h|7d|30d>Returns time-bucketed mining data. Bucket sizes: 24h→1h, 7d→6h, 30d→1d. Response: array of {"bucket": "...", "miner": "TAAL", "blocks": 5}
/stats/props/histogram?period=<24h|7d|30d>Returns time-bucketed block property averages (size, tx count, fees). Bucket sizes: 24h→1h, 7d→6h, 30d→1d.
/stats/protocols?days=<7>Returns protocol tag counts from recent transactions. Response: array of {"protocol": "ord", "tx_count": 5000}
/stats/protocols/histogram?period=<24h|7d|30d>Returns time-bucketed protocol tag counts. Bucket sizes: 24h→1h, 7d→6h, 30d→1d. Response: array of {"bucket": "...", "protocol": "ord", "tx_count": 5000}
/protocol/{key}/txs?page=&limit=Returns the paginated transaction list for a single protocol (same data as the /protocol/{key} HTML page), including the daily activity chart series. 404s if key is not a known protocol tag.
/protocol/{key}/history?days=<90>Returns daily tx-count history for a single protocol. days is clamped to 1–365 (default 90). Response: array of {"bucket": "...", "protocol": "ord", "tx_count": 5000}. 404s if key is not a known protocol tag.
/stats/richlist?page=Returns paginated rich list.
/stats/price-historyReturns historical BSV price data.
/stats/chart/<metric>Returns time-series data for a given stat metric. Valid metrics: tx_count, total_fees, avg_fee, avg_fee_rate, avg_tx_size, median_fee, median_tx_size, total_output_value, coin_days_destroyed, hashrate, difficulty, avg_block_size, total_size, avg_tx_rate, miners_revenue, circulating_supply, utxo_count, blockchain_size, total_tx_count, exchange_rate, mining. Supports ?days= query parameter (default 30, max 10000 — clamped to available history from genesis; long windows are downsampled). Note: exchange_rate is limited to 365 days (CoinGecko free tier).
Exchange Rate
/exchangerateReturns the current BSV exchange rate in USD.
/exchangeratesReturns BSV exchange rates in multiple currencies.
Mempool
/mempoolReturns mempool summary (tx count, size, usage, min fee).
/mempool/statsReturns mempool fee rate and size distribution histograms. Response includes tx_count, total_fee_bsv, avg_fee_bsv, fee_rate_buckets (sat/byte ranges), and size_buckets (byte ranges). Cached for 30 seconds.
/mempool/protocolsReturns detected protocol tags in mempool transactions with counts. Each entry has protocol, short, color, and count. Parses every mempool tx for protocol detection (ORD, BSV21, MAP, B, etc.). Cached for 60 seconds.
Mining
/miner/feesReturns current mining fee statistics.
/policyReturns the current fee policy.
Tools
/tools/decodeDecodes a raw transaction. Body: {"rawtx": "hex"}
/tools/script/decode?hex=Decodes a script hex string.
/tools/address/<addr>Converts an address between formats. Returns the base58, scripthash, and script hex for a given address.
/tools/peersReturns the connected node peers (proxies the BSV node's getpeerinfo). Each entry includes addr, services, conntime, version, subver, and traffic counters.
BSV-21 Tokens
/tokens?page=Returns a paginated list of all BSV-21 tokens.
/token/<tokenId>Returns details for a specific token (name, symbol, supply, holder count).
/token/<tokenId>/holders?page=Returns paginated list of token holders with balances.
/token/<tokenId>/history?page=Returns paginated token transfer history.
/address/tokens/balanceMulti-address batch token balances. Body: {"addresses": ["addr1", "addr2", ...]} (max 20 addresses per request). Returns an array keyed per address: {"address", "tokens": [{"token_id", "symbol", "decimals", "balance"}]}. Invalid or failed addresses return a per-item "error" with "tokens": [] rather than failing the whole batch.
/address/tokens/unspentMulti-address batch unspent token outputs. Body: {"addresses": ["addr1", "addr2", ...]} (max 20 addresses per request). Returns an array keyed per address: {"address", "utxos": [{"txid", "vout", "token_id", "symbol", "decimals", "amount", "block_height"}]}. Each address returns up to 100 most-recent unspent token UTXOs. When the returned list is not guaranteed complete — the 100 cap was reached, or (in Pebble mode) the spent-status scan hit its work guard on an address with a very large spent-token history — the entry includes "incomplete": true; treat such a list as partial. Invalid or failed addresses return a per-item "error" with "utxos": [].
Health
/healthReturns "ok" if the server is running. (Not under /api/v1 prefix.)
WebSocket
Connect to /ws for real-time updates. Subscribe by sending subscribe:<channel> (and unsubscribe:<channel>) as a text message. Valid channels:
blocks— new block notifications.mempool— mempool transaction feed.lock:address:<addr>— outputs paying to an address (alsolock:scripthash:<64-hex>).spend:address:<addr>— inputs spending from an address (alsospend:scripthash:<64-hex>).tx:<64-hex txid>— events for a specific transaction (currently:seenwhen it enters the mempool; lowercase hex).
Example: subscribe:lock:address:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa to watch payments to an address.
Webhooks
Get an HMAC-signed HTTP POST when a selector fires, instead of polling or holding a WebSocket connection open. Requires a self-serve account (see /account); the subscription cap depends on your active keys' tier — the free tier includes none.
/account/webhooksRegisters a subscription. Form fields: selector, callback_url. Session-authenticated (dashboard form), not part of the /api/v1 surface.
Selectors
Same grammar as the WebSocket channels below, EXCLUDING the bare blocks/mempool feeds — those stay public, no-auth, WebSocket-only:
lock:address:<addr>/lock:scripthash:<64-hex>— outputs paying to an address.spend:address:<addr>/spend:scripthash:<64-hex>— inputs spending from an address.tx:<64-hex txid>— events for a specific transaction (currently:seen).
Callback URL requirements
Must be https://. Every IP the hostname resolves to must be a public, globally-routable address — loopback, private (RFC1918), link-local (including the 169.254.169.254 cloud-metadata address), and unspecified addresses are all rejected, both at registration time and again at delivery time. The delivery request never follows redirects.
Signature verification
Each delivery carries:
X-Webhook-Signature: sha256=<hex HMAC-SHA256 of the raw request body, keyed by your subscription's secret>X-Webhook-Event: <selector>Content-Type: application/json
The secret is generated server-side and shown exactly once when you create the subscription — store it; it cannot be recovered, only rotated by deleting and re-creating the subscription. Recompute the HMAC over the raw body and compare using a constant-time comparison before trusting a delivery.
Retry, disable, and delivery semantics
A failed delivery (anything other than a 2xx response, including a timeout) is retried up to 3 times with 1s/5s/25s backoff. A subscription that fails 10 consecutive deliveries is automatically disabled (visible on the dashboard); re-enable by deleting and re-creating it.
Webhooks are best-effort and at-least-once in normal operation, the same idempotency posture as most webhook providers — key on txid (plus status for tx: events) to de-duplicate on your end. Delivery is owned by exactly one backend node at a time; during the brief window around a failover (the prior owner stops, the new one takes over), events observed in that window are not delivered — webhooks are therefore at-most-once across a failover. Treat webhooks as a low-latency convenience and reconcile against the REST API for anything that must not be missed.
WhatsonChain-Compatible API
A WhatsonChain-compatible API is available at /api/v1/bsv/main. This allows existing applications built for the WoC API to work with BananaBlocks as a drop-in replacement. See the WhatsonChain API docs for endpoint details. BSV-21 token endpoints (/token/bsv21/...) are included — see the BSV-21 (Beta) contract for the covered subset.