-
Notifications
You must be signed in to change notification settings - Fork 0
REST API
Alessandro Siniscalchi edited this page Feb 2, 2026
·
10 revisions
- The REST service starts when you run brc721 with no subcommand (daemon mode). Wallet and tx subcommands do not start the API.
- By default the server binds to
127.0.0.1:8083. Override it with--api-listen <host:port>or by settingBRC721_API_LISTEN. Bind only to trusted interfaces unless you have a reverse proxy or firewall in front of it. - The API is implemented with Axum and currently exposes read-only endpoints for node health, sync progress, collections, ownership, and address assets.
- Token IDs and slot range values are serialized as strings to avoid JSON integer precision loss.
- There is no built-in authentication yet. The
BRC721_API_TOKENenvironment variable is reserved for a future release but is not enforced in the current build. - Until token support lands, restrict access by:
- Binding to
127.0.0.1(default) and tunneling through SSH, Tailscale, or a reverse proxy. - Placing the service behind an HTTPS gateway that enforces its own authentication layer.
- Avoiding public exposure of the port entirely.
- Binding to
- Returns a plain status payload so you can wire the service into probes.
- Response
200 OK:{ "status": "ok", "uptimeSecs": 42 }uptimeSecscounts seconds since the REST process started.
- Reports the latest block the scanner persisted. If no blocks have been processed yet,
lastis null. - Responses:
-
200 OKwith the payload shown below. -
500 Internal Server Errorif the underlying storage layer (SQLite) fails.
-
- Example response:
{ "last": { "height": 923580, "hash": "0000000000000000000example" } }
- Lists every known collection, sorted by collection id.
- Responses:
-
200 OKwith the payload shown below. -
500 Internal Server Errorif the underlying storage layer (SQLite) fails.
-
- Example response:
The
{ "collections": [ { "id": "850123:0", "height": 850123, "txIndex": 0, "evmCollectionAddress": "0x1234abcd00000000000000000000000000000000", "rebaseable": true } ] }idformat is<height>:<txIndex>, matching the scanner's internal key.
- Fetches a single collection by its
<height>:<txIndex>identifier. - Responses:
-
200 OKwith the same body shape as entries in/collections. -
400 Bad Requestif the id cannot be parsed (wrong delimiter, non-numeric height, etc.). -
404 Not Foundif the id is well-formed but unknown. -
500 Internal Server Errorif the underlying storage layer (SQLite) fails.
-
- Returns the current ownership status for a specific token that belongs to a registered Bitcoin collection.
-
collection_idfollows the<height>:<txIndex>format. -
token_idmust be a 256-bit TokenID expressed as a base-10 string. - Responses:
-
200 OKwith either an initial owner or registered owner payload. -
400 Bad Requestif the collection id or token id is malformed. -
404 Not Foundwhen the collection does not exist in storage. -
500 Internal Server Errorif storage lookups fail.
-
-
utxoHeightandutxoTxIndexpoint to the block/tx that created the current ownership UTXO (not the original NFT mint). -
owneris the address derived from the output script when available.
Example response for the initial-owner case:
{
"collectionId": "850123:0",
"height": 850123,
"txIndex": 0,
"tokenId": "1043755606923009056510026266671580063926660113753943375567",
"ownershipStatus": "INITIAL_OWNER",
"ownerH160": "0x00112233445566778899aabbccddeeff00112233"
}Example response for the registered-owner case:
{
"collectionId": "850123:0",
"height": 850123,
"txIndex": 0,
"tokenId": "1043755606923009056510026266671580063926660113753943375567",
"ownershipStatus": "REGISTERED_OWNER",
"ownerH160": "0xdeadbeef00112233445566778899aabbccddeeff",
"owner": "bcrt1q...",
"txid": "0000000000000000000000000000000000000000000000000000000000000000",
"vout": 1,
"utxoHeight": 840001,
"utxoTxIndex": 2
}- Returns the currently indexed BRC-721 ownership ranges for a single Bitcoin address.
- The server derives
ownerH160ashash160(scriptPubKey)for the address and returns the unspent ownership UTXOs associated with that script hash. - Responses:
-
200 OKwith the payload shown below. -
400 Bad Requestif the address is malformed or does not match the daemon network. -
500 Internal Server Errorif the underlying storage layer (SQLite) fails.
-
- Example response:
{ "address": "bcrt1q...", "ownerH160": "0x00112233445566778899aabbccddeeff00112233", "utxos": [ { "collectionId": "850123:0", "txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 1, "initOwnerH160": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "utxoHeight": 840001, "utxoTxIndex": 2, "slotRanges": [ { "start": "0", "end": "9" }, { "start": "42", "end": "42" } ] } ] }
- Returns all indexed BRC-721 ownership ranges present in a specific outpoint, along with the owner and UTXO creation height/tx index.
-
owneris the address derived from the output script when available. - Responses:
-
200 OKwith the payload shown below. -
400 Bad Requestif the txid or vout is malformed. -
404 Not Foundif the outpoint has no unspent ownership UTXOs. -
500 Internal Server Errorif the underlying storage layer (SQLite) fails.
-
- Example response:
{ "txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 1, "ownerH160": "0xdeadbeef00112233445566778899aabbccddeeff", "owner": "bcrt1q...", "utxoHeight": 840001, "utxoTxIndex": 2, "assets": [ { "collectionId": "850123:0", "initOwnerH160": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "slotRanges": [ { "start": "0", "end": "9" }, { "start": "42", "end": "42" } ] } ] }
- All
4xx/5xxresponses include a JSON payload with a short, human-readable message:{ "message": "invalid address" } - Unknown endpoints return
404with:Check your logs for more context; the server logs validation errors at warn and storage failures at error.{ "message": "endpoint not found" } - When you receive a
500, retry with exponential backoff. The storage call may have raced with a reset or compaction, and simply waiting a second before the next request usually suffices.
- The REST API is still experimental. Expect occasional breaking changes in field names or payload structure until the project declares a stable release.
- Breaking changes will be noted in the release notes and in this document. Pin your automation to a specific binary version if you require stability.
# Health probe
curl -s http://127.0.0.1:8083/health | jq
# Check scanner progress
curl -s http://127.0.0.1:8083/state
# List every collection
curl -s http://127.0.0.1:8083/collections | jq '.collections | length'
# Fetch a specific collection by height:txIndex
curl -s http://127.0.0.1:8083/collections/850123:0
# Fetch BRC-721 assets for a Bitcoin address
curl -s http://127.0.0.1:8083/addresses/bcrt1q.../assets | jq
# Fetch BRC-721 assets for a specific outpoint
curl -s http://127.0.0.1:8083/utxos/<txid>/<vout>/assets | jq