Query any Bitcoin address and get its BTC balance, Rune tokens, and Ordinals inscriptions in a single API call.
Bitcoin's ecosystem has fragmented into at least four data layers — mainnet UTXOs (mempool.space), Ordinals inscriptions (Ordiscan), Runes fungible tokens (BestInSlot), and L2 activity — each with its own specialized explorer and incompatible API schema. A DeFi protocol building on Runes can't answer "what is the Runes token distribution for ticker X?" without combining three separate APIs that disagree on data formats. No existing tool maintains the semantic link between a Runes token, the UTXO it lives on, the inscription that may also be on that UTXO, and the mempool status of the transaction that last touched it.
# If running on chainwatch, tunnel API locally first:
# ssh -N -L 3300:127.0.0.1:3300 root@chainwatch
# Health
curl http://127.0.0.1:3300/health
# Unified address lookup (real non-empty sample)
curl "http://127.0.0.1:3300/v1/addresses/bc1p9fh9y93vemenx7dx6ugv588yv7z8qxun6t05tttxd0z7ujf20f5qa5ntx3?include=utxo_breakdown"
# Rune analytics + oracle view
curl "http://127.0.0.1:3300/v1/runes/880005:828"
curl "http://127.0.0.1:3300/v1/runes/880005:828/stacks-oracle"Unified address lookup
Get a wallet's complete Bitcoin position — BTC balance, all Rune token balances (with the UTXOs they live on), and all Ordinals inscriptions — in one request:
GET /v1/addresses/{bitcoin_address}?include=utxos,inscriptions,runes,mempool{
"address": "bc1p...",
"summary": {
"btc_balance_sats": 8200000,
"utxo_count": 12,
"inscription_count": 4,
"runes_held": 3
},
"runes_balances": [
{
"rune_id": "840000:3",
"ticker": "UNCOMMON•GOODS",
"amount": "1000",
"utxo_txid": "abc123...",
"utxo_vout": 0
}
]
}Runes token analytics
Holder concentration, gini coefficient, mint progress, and 24h transfer volume for any Rune:
GET /v1/runes/840000:3{
"rune_id": "840000:3",
"ticker": "UNCOMMON•GOODS",
"supply": { "minted": "284000000", "circulating": "283818000", "mint_progress_pct": 83.2 },
"holders": { "total": 182000, "top_10_pct": 0.28, "gini_coefficient": 0.71 },
"transfers_24h": 4821
}Stacks oracle — Rune holder data for Clarity contracts
Returns holder distribution in a format Stacks DeFi contracts can consume directly:
GET /v1/runes/{rune_id}/stacks-oracleWebSocket streaming is out of scope for the grant MVP.
Ordisat runs a Bitcoin full node and processes every block through three parallel indexers:
- UTXO indexer — tracks the full UTXO set as inputs are spent and outputs are created
- Runes indexer — decodes OP_RETURN Runestones (LEB128 encoding), tracks UTXO-level balances and transfer history; Runes balances are UTXO-attached, not account-attached
- Ordinals indexer — tracks inscription genesis, transfers, and sat rarity from taproot witness data
All state lands in PostgreSQL. The REST API queries the DB directly with no live Bitcoin RPC calls in the hot path — address queries hit a single indexed rune_balances row.
See PRD.md for the full architecture, data model, and API specification.
Ordisat ships as a Docker Compose stack now:
cp .env.example .env
# edit .env and set strong BITCOIN_RPC_PASS / POSTGRES_PASSWORD
docker compose up -d --buildServices:
bitcoind(Bitcoin Core)postgres(state store)indexer(checkpoint sync + runes processing)api(loopback by default at127.0.0.1:3300)
For endpoint and cross-check results, see VALIDATION.md.
See MEMORY.md for the implementation handoff guide — build order, architecture decisions, and the minimum build needed to unlock grant funding.