Architecture

Understand the architecture of the Stacks Blockchain API.

Stacks Blockchain API architecture

Overview

The Stacks Blockchain API sits between Stacks nodes and the apps that use chain data. It does three things:

  • Indexes the chain. It receives events from a Stacks node and stores them as relational data in PostgreSQL.
  • Serves that data. Its REST endpoints and real-time subscriptions read from PostgreSQL, so they can answer questions a node cannot, such as the full transaction history of an account.
  • Proxies the node. Requests to the node's own /v2/* RPC endpoints pass through the API to a Stacks node.

Event ingestion

A Stacks node doesn't keep an account's transaction history, and it isn't built to serve many clients at once. The API fills that gap by indexing everything the node reports.

The API runs an event server (port 3700 by default) that a Stacks node pushes events to over HTTP. To connect a node, add an event observer to its configuration:

[[events_observer]]
endpoint = "localhost:3700"
events_keys = ["*"]
timeout_ms = 60_000

The node then sends:

  • New blocks, with each transaction and what it produced: asset transfers, smart contract logs, and execution costs
  • New burn blocks from the Bitcoin chain
  • Mempool activity: newly received transactions, and transactions dropped from the mempool
  • Signer data: StackerDB chunks and block proposal responses

The API decodes these and writes them to PostgreSQL. The ingestion code is in src/event-stream.

Ingesting from Stacks Node Publisher

Instead of receiving events directly from a node, the API can consume them from Stacks Node Publisher (SNP), which stores every node event in PostgreSQL and streams it to consumers over Redis. This decouples the API from any single node, and SNP can replay history from any block, so a new API instance can sync without a node re-sending events.

Set SNP_EVENT_STREAMING=true and SNP_REDIS_URL to enable it. SNP_BLOCKS_ONLY_STREAMING=true limits the stream to blocks and burn blocks, which speeds up a sync from genesis.

Serving data

Endpoints are built with Fastify, with request and response schemas defined in TypeBox. Route definitions are in src/api/routes.

  • REST endpoints under /extended/v3, plus the /extended/v2 endpoints that have no v3 successor, read from PostgreSQL. See the API reference for the full list. Older /extended/v1 endpoints are deprecated; see Migrating from v1 to v3.
  • Real-time subscriptions for blocks, mempool transactions, transaction updates, address activity, and NFT events are available over WebSocket (JSON-RPC 2.0) and Socket.IO. See WebSockets.

Most responses carry an ETag tied to the state they were computed from, such as the chain tip, the mempool, or a specific transaction. Send it back in an If-None-Match header, and the API answers 304 Not Modified when nothing has changed, without recomputing the response.

Stacks node RPC proxy

A Stacks node exposes its own set of HTTP endpoints, referred to as RPC endpoints. The API forwards requests for the node's /v2/* endpoints to the Stacks node it is configured with, and returns the node's response unchanged. Commonly used RPC endpoints include:

EndpointPurpose
POST /v2/transactionsBroadcast a transaction
POST /v2/fees/transactionEstimate the fee for a transaction
POST /v2/contracts/call-read/{deployer_address}/{contract_name}/{function_name}Call a read-only Clarity function
GET /v2/accounts/{principal}Get an account's balance and nonce
GET /v2/poxGet current Proof of Transfer information

See the Stacks Node RPC API for every RPC endpoint.

Proxied requests take longer than requests the API answers from its own database, because each one round-trips to a node. Avoid calling them at high frequency when an API endpoint serves the same data.

The API forwards to a single configured node address (STACKS_CORE_PROXY_HOST and STACKS_CORE_PROXY_PORT, falling back to the node's RPC host and port). To spread proxied traffic across several nodes, point it at a load balancer.

Fee estimation can differ from the node's

When STACKS_CORE_FEE_ESTIMATOR_ENABLED=true, the API adjusts POST /v2/fees/transaction responses. If recent blocks had spare capacity, it returns the minimum fee for the transaction's size. Otherwise it returns the node's estimate scaled by a configurable multiplier, never below that minimum. It is disabled by default.

Run modes

The same codebase can run as a single instance or be split up to scale, controlled by STACKS_API_MODE:

ModeRunsUse
DefaultEvent server and API serverA single self-contained instance
readonlyAPI server onlyServe traffic from a database another instance writes to
writeonlyEvent server onlyIngest into PostgreSQL without serving endpoints

A common production layout is one write-only instance ingesting events and several read-only instances behind a load balancer, all sharing one PostgreSQL database. Read-only instances fully support WebSocket and Socket.IO subscriptions.

OpenAPI specification and client

The OpenAPI specification is generated from the Fastify route schemas, so it can't drift from the endpoints it describes. The committed openapi.yaml is regenerated with each release and excludes deprecated endpoints.

The specification powers:

Running the API yourself

For local development, Clarinet runs a full devnet — Bitcoin node, Stacks node, API, and PostgreSQL — with clarinet devnet start.

For production, use the hirosystems/stacks-blockchain-api Docker image. The repository README covers configuration, run modes, event replay, and development setup.

How is this guide?