API reference
Bitcoin API documentation
A single REST API over the fully-indexed Bitcoin blockchain. Authenticate with a bearer key, then query addresses, transactions, blocks, UTXOs, on-chain metrics and the rich list, or drop to SQL. Here is everything you need to make your first request.
Introduction
The BitcoinDatabase API is organized around predictable, resource-oriented REST. Every request is sent over HTTPS, accepts and returns JSON, and authenticates with a bearer key. Address and transaction history reaches back to the 2009 genesis block, and new blocks are indexed within seconds. The base URL for all endpoints is:
https://bitcoindatabase.com/v1
Authentication
Authenticate every request by passing your secret key in the Authorization header as a bearer token. Keep your key secret, on a server and out of client-side code. You get a key when you create an account.
Authorization: Bearer $BITCOINDATABASE_API_KEY
GET /v1/address/{addr}
Look up a single address. Returns its confirmed balance to the satoshi, transaction count, first and last seen, and any entity label such as exchange, miner or service.
curl https://bitcoindatabase.com/v1/address/bc1q...x7 \
-H "Authorization: Bearer $BITCOINDATABASE_API_KEY"
import requests
r = requests.get(
"https://bitcoindatabase.com/v1/address/bc1q...x7",
headers={"Authorization": f"Bearer {API_KEY}"},
)
data = r.json()
const res = await fetch("https://bitcoindatabase.com/v1/address/bc1q...x7", {
headers: { Authorization: `Bearer ${process.env.BITCOINDATABASE_API_KEY}` },
});
const data = await res.json();
Response · 200 OK
{
"address": "bc1q...x7",
"balance_sat": 182734991,
"tx_count": 47,
"first_seen": "2017-03-11",
"label": { "entity": "exchange", "name": "example-exchange" }
}
Core endpoints
| Endpoint | Returns |
|---|---|
| GET /v1/address/{addr} | Address balance, tx count, first or last seen and entity label. |
| GET /v1/address/{addr}?block={height} | The confirmed balance at the end of a block. ?at= takes a unix time or ISO date and uses the last block mined by then. 10 credits, same plan history window as every lookup. An address with 1,000 or more transactions after that block is refused as too long to walk back, at the same 10 credits, since the history was read. |
| GET /v1/address/{addr}/balance-history | End of day balance for each UTC day from from to to (ISO dates, up to 3660 days). 10 credits. A range reaching back past 1,000 or more transactions is refused as too long to walk back, at the same 10 credits, since the history was read. |
| GET /v1/address/{addr}/txs | Paged transaction history for an address, newest first. |
| GET /v1/address/{addr}/utxos | Unspent outputs for that address. |
| POST /v1/addresses/batch | Up to 10,000 addresses in one batch, {"addresses": [...], "block": 900000} with an optional block or at (up to 5,000 addresses). A repeated address is counted once. One credit per address, 10 per address as of a block, answered 202 with an id; rows the index could not answer are credited back when the batch completes, rows refused as too long to walk back keep their charge. |
| GET /v1/addresses/batch/{id} | The batch status, total and rows (balance and tx count, plus first and last seen for a batch without a block), 1,000 per page or all of them with ?format=csv. |
| GET /v1/tx/{txid} | A transaction with inputs, outputs, fee and confirmations. |
| GET /v1/block/{height} | A block by height with header fields and its transactions. |
| GET /v1/block/{hash} | The same block answer looked up by its hash. |
| GET /v1/chain | Chain tip height and hash, difficulty, median time, mempool size and fee tiers. |
| GET /v1/fees | Fee rates in sat/vB by confirmation target, with next block, half hour, hour and economy tiers. |
| GET /v1/xpub/{xpub} | Derived addresses and combined balance for an extended public key. |
| GET /v1/mempool | The unconfirmed set and fee-rate estimates. |
| POST /v1/tx/broadcast | Relay a signed raw transaction to the network and get its txid back. |
| GET /v1/metrics/{metric} | An on-chain metric series: active addresses, realized cap, realized price, market cap, supply in profit, SOPR, exchange flows, hashrate, difficulty and block fees. |
| GET /v1/price/ohlcv | OHLCV candles in USD. interval=1d or 1h, optional from and to (ISO date or unix time), limit up to 10000, format=json or csv. Each candle is labelled by the UTC start of its bucket and says whether it is closed. |
| GET /v1/export/{dataset}.csv | A whole dataset in bulk, as CSV or as Parquet, on the Scale plan. |
| GET /v1/addresses/top | The rich list, the top addresses ranked by balance. |
| GET /v1/screen/{addr} | Address screening on the Enterprise plan: sanctions list matches, exposure over direct and near counterparties, and a risk signal with the transactions behind it. |
| GET, POST /v1/screening/book | Your screening book: up to 1,000 addresses per request, rescreened automatically whenever a new sanctions list is published. ?changed=1 returns entries whose signal moved. |
| DELETE /v1/screening/book/{addr} | Stop watching an address in your screening book. |
| POST /v1/tx/decode | Decode a raw transaction. Body {"hex": "..."}, up to 400,000 bytes. Returns txid, wtxid, version, locktime, size, vsize, weight, inputs with their witness items, and outputs with value, script type and address. Malformed hex answers 422 invalid_transaction. |
| GET /v1/transactions/large | Recent large transfers, newest first. min_btc (default 100, at least 10), optional min_usd, since_height or since (ISO time), limit 1 to 500 (default 100). The size is the output total, change included; scanned_through_height says how far blocks have been read. |
| GET, POST /v1/webhooks | Webhooks on the Scale plan. Posting the same target and url again changes its threshold and keeps its secret. A webhook switched off when a plan lapses is listed under switched_off with the reason and starts again, with the same secret, when posted again. type is address (default, with address), tx (with txid) or large_transfer (with min_btc of at least 10, min_usd, or both; when both are given, both must be met). Only transfers of 10 BTC or more are tracked, so a min_usd below the value of 10 BTC behaves as 10 BTC. confirmations 0 to 6 applies to the address and tx types (default 1; 0 delivers at mempool sighting). Events: address.changed, address.transaction, address.gap (a burst too large to deliver one by one; backfill that height range from /v1/address/{addr}/txs), tx.confirmations, large_transfer, each signed in X-BitcoinDatabase-Signature. Subscriptions are checked continuously, and a delivery typically arrives within a minute or two of the event, longer when an account watches hundreds of addresses, because checks share a per-minute read budget. Up to 1,000 active webhooks on Scale and 10,000 on Enterprise. |
| DELETE /v1/webhooks/{id} | Stop a webhook subscription. |
GET /v1/tx/{txid}
Resolve a transaction by its hash. Returns the full set of inputs and outputs, the fee, the block it was mined in and its current confirmation count. Unconfirmed transactions in the mempool come back with a confirmations value of zero.
curl https://bitcoindatabase.com/v1/tx/4a5e1e4b...c8d \
-H "Authorization: Bearer $BITCOINDATABASE_API_KEY"
Response · 200 OK
{
"txid": "4a5e1e4b...c8d",
"block_height": 847291,
"confirmations": 312,
"fee_sat": 2140,
"inputs": [ { "address": "bc1q...a2", "value_sat": 5000000 } ],
"outputs": [ { "address": "bc1q...x7", "value_sat": 4997860 } ]
}
Address screening and the screening book
On the Enterprise plan, GET /v1/screen/{addr} checks an address against every entry of the published OFAC SDN list, then reads its transactions to find direct counterparties (who paid it and whom it paid) and near counterparties (who funded the coins it received). Each counterparty is matched against the list and against entity labels. The answer carries a risk signal (low, medium, high or severe), the reasons, every finding with the transaction ids behind it, the list version it was made against, the block height, and how much of the history was read. A screening costs 10 credits.
Add addresses to your book with POST /v1/screening/book and a JSON body {"addresses": [...]}. Each new address is matched against the current list at once, and every entry is rescreened automatically when a new list version arrives against the address and the counterparties its last screening read, so a new designation among them shows up in GET /v1/screening/book?changed=1. Each entry says whether that screening read the full history (trace_complete); for a busy address it covers the newest transactions. A signal is context for your own compliance review, not a verdict on anyone.
curl https://bitcoindatabase.com/v1/screen/bc1q...x7 \
-H "Authorization: Bearer $BITCOINDATABASE_API_KEY"
SQL access
From the Growth plan and up, you can query the indexed chain with raw SQL. Write your own joins across addresses, transactions, blocks, UTXOs and metric tables, reproduce any dashboard number from the underlying rows, and export results in bulk. A SQL query costs more credits than a single REST lookup.
POST /v1/sqlcurl https://bitcoindatabase.com/v1/sql \
-H "Authorization: Bearer $BITCOINDATABASE_API_KEY" \
-d '{ "query": "SELECT day, active_addresses FROM metrics_daily ORDER BY day DESC LIMIT 30" }'
There is no database connection to configure. SQL is sent over HTTPS to POST /v1/sql and authenticated with the same bearer API key as the REST endpoints. BitcoinDatabase does not expose a Postgres wire protocol listener, so there is no host, port, database user or password, and clients such as psql or a desktop SQL browser cannot attach directly. Anything that can make an HTTP request can run a query.
The schema tables you can query
SQL queries run against a normalized model of the chain. These are the core tables and the columns most queries reach for. Every row is derived from the indexed chain itself, so a query returns the same answer as recomputing it from raw blocks.
| Table | One row is | Columns you will use most |
|---|---|---|
| blocks | A confirmed block | height, hash, time, tx_count |
| transactions | A transaction in a block | txid, block_height, fee_btc, size, weight |
| outputs | One output of one transaction | txid, vout, address, value_btc, script_type, spent, created_at, price_at_creation_usd |
| inputs | One input, linked to the output it spends | spending_txid, prev_txid, prev_vout |
| metrics_daily | One day of precomputed on-chain metrics | day, active_addresses, tx_count, fees_btc |
| price_candles | One OHLCV candle in USD, daily (1d) or hourly (1h), from August 2011 | resolution, bucket_start, day, open, high, low, close, volume_btc, closed |
| metric_points | One day of a market and on-chain series, the same points /v1/metrics serves | id, metric, day, value, extra, measured_at |
Two joins carry most analysis. inputs links to outputs on prev_txid and prev_vout, which is how you follow coins from where they were created to where they were spent. transactions links to blocks on block_height, which is how you put a timestamp on anything.
An unspent output is simply spent = false, so a balance is a sum over that filter and the UTXO set is a view rather than a separate product. Because script_type sits on every output, any query can be filtered or grouped by address type.
SQL query examples
Four worked queries against the tables above, covering the shapes people ask for most: a balance, a historical series, a flow trace and a cohort.
SELECT sum(value_btc) AS balance_btc, count(*) AS utxos
FROM outputs
WHERE address = '34xp4vRoCGJym3xR7yCVPFHoCNxv4Twseo'
AND spent = false;
SELECT o.script_type,
count(*) AS outputs,
round(sum(o.value_btc), 8) AS btc
FROM outputs o
JOIN transactions t ON t.txid = o.txid
WHERE t.block_height = 963670
GROUP BY o.script_type
ORDER BY outputs DESC;
SELECT o.address AS from_addr, i.spending_txid, o2.address AS to_addr, o2.value_btc
FROM outputs o
JOIN inputs i ON i.prev_txid = o.txid AND i.prev_vout = o.vout
JOIN outputs o2 ON o2.txid = i.spending_txid
WHERE o.txid = '7b77e72b87887b494fa428990dab03db3ce91305a48cd174073724ed2d4bb0ae';
SELECT sum(value_btc) AS old_supply_btc
FROM outputs
WHERE spent = false
AND created_at < now() - interval '1 year';
The same patterns extend to the rich list, exchange reserve totals over any address set you define, and historical series rebuilt from the rows rather than read off a chart.
Rate limits and credits
Each plan includes a monthly pool of API credits and a per-second request limit. Calls cost credits by type, so light lookups are cheap and heavier queries cost more. If you exceed your rate, the API returns 429 with a Retry-After header.
| Plan | Credits / mo | Requests / s |
|---|---|---|
| Developer | 500K | 10 |
| Growth | 5M | 50 |
| Scale | 50M | 250 |
| Enterprise | 100M | 500 |
Any language, plain HTTP
The REST API is plain JSON over HTTPS, so it works from any language with an HTTP client: curl, Python's requests, Node's fetch, or whatever your stack already uses. No SDK to install first.
curl https://bitcoindatabase.com/v1/address/{addr} \
-H "Authorization: Bearer $KEY"
Webhooks
Subscribe an address or transaction to a webhook URL and BitcoinDatabase posts to your endpoint on new activity and on confirmation changes, so you never poll the chain. Each delivery is signed, so you can verify it came from us before you ingest the data.
POST /hooks/bitcoindatabase
X-Bdb-Signature: t=...,v1=...
Documentation FAQ
How do I connect to the BitcoinDatabase SQL database? +
POST /v1/sql with your API key in an Authorization: Bearer header and the statement in a JSON body. There is no Postgres wire protocol endpoint, so there is no host, port, database user or password to configure, and tools that expect a direct connection string will not attach.What credentials do I need for the API? +
Authorization: Bearer $BITCOINDATABASE_API_KEY on every request over HTTPS. There is no separate database credential, no OAuth flow and no signed request scheme. Keep the key server-side, because anything holding it can spend your credits.What is the database schema? +
blocks, transactions, outputs, inputs and metrics_daily. Outputs carry the address, value, script type and whether the output is spent, which is what makes balances, UTXO sets and address type breakdowns all queries over one table. Candles live in price_candles and the daily market and on-chain series in metric_points, so a day close joins to that day's exchange flows or realized price in one query. The full column listing is in the schema section above.Is SQL access included on every plan? +
How much does the API cost? +
What happens when I hit the rate limit? +
429 with a Retry-After header telling you how long to wait. Back off for that interval rather than retrying immediately. Rate limiting is per second, and separate from your monthly credit pool, so you can be inside your credit allowance and still be throttled by burst rate.Can I query historical state, not just the current tip? +
Do I need to install an SDK? +
requests, Node's fetch, or whatever your stack already has. There is nothing to install before your first call.Where to go next
The endpoints above are the primitives. Most work starts from a specific question, and these pages show the query shapes for the common ones: address lookup, address balances at scale, transaction data, SQL over the chain, on-chain metrics and the comparison of Bitcoin APIs if you are still choosing.
Informational data only. BitcoinDatabase serves on-chain data and analytics, not financial, investment or legal advice. AML and risk features surface labels, signals and flows to support a regulated team's own review, with no accusations and no deanonymization. Read the compliance policy.
Make your first API call
Get a key, send a request, and get an address, transaction, block or metric back from the fully-indexed chain. Informational on-chain data only.