mod compact;
pub use compact::ApiJson;
use aide::openapi::{Contact, Info, License, OpenApi, Tag};
use crate::VERSION;
pub fn create_openapi() -> OpenApi {
let info = Info {
title: "Bitcoin Research Kit".to_string(),
description: Some(
r#"API for querying Bitcoin blockchain data, mempool state, and on-chain series.
### Features
- **[Mempool.space](https://mempool.space/docs/api/rest) compatible**: Blocks, transactions, addresses, mining, fees, and mempool endpoints match the mempool.space REST API
- **Series**: Thousands of on-chain time-series across multiple indexes (date, block height, etc.)
- **Multiple formats**: JSON and CSV output
- **LLM-optimized**: [`/llms.txt`](/llms.txt) for discovery, [`/api.json`](/api.json) compact OpenAPI spec for tool use (full spec at [`/openapi.json`](/openapi.json))
### Quick start
```bash
curl -s https://bitview.space/api/blocks/tip/height
curl -s https://bitview.space/api/v1/fees/recommended
curl -s https://bitview.space/api/mempool
curl -s https://bitview.space/api/series/search?q=price
```
### Errors
All errors return structured JSON with a consistent format:
```json
{
"error": {
"type": "not_found",
"code": "series_not_found",
"message": "'foo' not found, did you mean 'bar'?",
"doc_url": "/api"
}
}
```
- **`type`**: Error category — `invalid_request` (400), `forbidden` (403), `not_found` (404), `unavailable` (503), or `internal` (500)
- **`code`**: Machine-readable error code (e.g. `invalid_address`, `series_not_found`, `weight_exceeded`)
- **`message`**: Human-readable description
- **`doc_url`**: Link to API documentation
### Client Libraries
- [JavaScript](https://www.npmjs.com/package/brk-client)
- [Python](https://pypi.org/project/brk-client/)
- [Rust](https://crates.io/crates/brk_client)
### Links
- [GitHub](https://github.com/bitcoinresearchkit/brk)
- [Bitview](https://bitview.space) - Web app built on this API"#
.to_string(),
),
version: format!("v{VERSION}"),
contact: Some(Contact {
name: Some("Bitcoin Research Kit".to_string()),
url: Some("https://github.com/bitcoinresearchkit/brk".to_string()),
email: Some("hello@bitcoinresearchkit.org".to_string()),
..Contact::default()
}),
license: Some(License {
name: "MIT".to_string(),
url: Some(
"https://github.com/bitcoinresearchkit/brk/blob/main/docs/LICENSE.md".to_string(),
),
..License::default()
}),
..Info::default()
};
let tags = vec compatible.*"
.to_string(),
),
..Default::default()
},
Tag {
name: "Addresses".to_string(),
description: Some(
"Query Bitcoin address data including balances, transaction history, and UTXOs. \
Supports all address types: P2PKH, P2SH, P2WPKH, P2WSH, and P2TR.\n\n\
*[Mempool.space](https://mempool.space/docs/api/rest) compatible.*"
.to_string(),
),
..Default::default()
},
Tag {
name: "Blocks".to_string(),
description: Some(
"Retrieve block data by hash or height. Access block headers, transaction lists, \
and raw block bytes.\n\n\
*[Mempool.space](https://mempool.space/docs/api/rest) compatible.*"
.to_string(),
),
..Default::default()
},
Tag {
name: "Mining".to_string(),
description: Some(
"Mining statistics including pool distribution, hashrate, difficulty adjustments, \
block rewards, and fee rates across configurable time periods.\n\n\
*[Mempool.space](https://mempool.space/docs/api/rest) compatible.*"
.to_string(),
),
..Default::default()
},
Tag {
name: "Fees".to_string(),
description: Some(
"Fee estimation and projected mempool blocks.\n\n\
*[Mempool.space](https://mempool.space/docs/api/rest) compatible.*"
.to_string(),
),
..Default::default()
},
Tag {
name: "Mempool".to_string(),
description: Some(
"Monitor unconfirmed transactions. Get mempool statistics, \
transaction IDs, fee histogram, and recent transactions.\n\n\
*[Mempool.space](https://mempool.space/docs/api/rest) compatible.*"
.to_string(),
),
..Default::default()
},
Tag {
name: "Transactions".to_string(),
description: Some(
"Retrieve transaction data by txid. Access full transaction details, confirmation \
status, raw hex, merkle proofs, and output spend information.\n\n\
*[Mempool.space](https://mempool.space/docs/api/rest) compatible.*"
.to_string(),
),
..Default::default()
},
Tag {
name: "Metrics".to_string(),
description: Some("Deprecated — use Series".to_string()),
extensions: [("deprecated".to_string(), serde_json::Value::Bool(true))].into(),
..Default::default()
},
];
OpenApi {
info,
tags,
..OpenApi::default()
}
}