Skip to content

stx-labs/stacks-mesh-api

Repository files navigation

Stacks Mesh API

A Mesh API (formerly Rosetta API) implementation for the Stacks blockchain. It provides a standardized set of endpoints for reading blockchain data, constructing transactions, and interacting with smart contracts, all through a single JSON-RPC interface that communicates directly with a Stacks node.

Features

  • Network status -- query blockchain identity, sync status, connected peers, and supported operation types
  • Block and transaction data -- retrieve full Nakamoto blocks with decoded operations (transfers, contract calls, PoX events, etc.)
  • Account balances -- look up STX balances, nonces, and stacking lock status (including historical queries)
  • Transaction construction -- offline-compatible flow for building, signing, and broadcasting STX transfers, contract calls, and contract deployments
  • Smart contract reads -- call read-only functions, inspect ABIs, read source code, and query data vars and map entries
  • Mesh specification v1.5.1 compliant

Limitations

  • Only Nakamoto blocks (Stacks 3.x+) are supported. This API targets the Nakamoto consensus rules and does not handle legacy pre-Nakamoto block formats. Running it against a node that has not activated Nakamoto will produce errors or incomplete data.

Requirements

  • Node.js >= 24
  • A running Stacks node with the RPC endpoint accessible

Stacks node requirements

The Stacks node does not need any special configuration. A regular chain follower is sufficient. However, the node must have an auth_token configured under [connection_options] in its Stacks.toml config file:

[connection_options]
auth_token = "some-secret-token"

This token must match the STACKS_CORE_RPC_AUTH_TOKEN environment variable passed to the Mesh API (see below).

Configuration

The API is configured via environment variables (a .env file is also supported):

Variable Default Description
API_HOST 0.0.0.0 Address the HTTP server binds to
API_PORT 3000 Port the HTTP server listens on
STACKS_CORE_RPC_HOST (required) Hostname of the Stacks node RPC
STACKS_CORE_RPC_PORT 20443 Port of the Stacks node RPC
STACKS_CORE_RPC_AUTH_TOKEN (required) Auth token for the Stacks node RPC
STACKS_CORE_RPC_TIMEOUT_MS 10000 RPC request timeout in milliseconds
TOKEN_METADATA_CACHE_SIZE 1000 Max entries in the token metadata LRU cache
TOKEN_METADATA_CACHE_TTL_MS 86400000 Token metadata cache TTL (default 24 h)
CONTRACT_ABI_CACHE_SIZE 100 Max entries in the contract ABI LRU cache
CONTRACT_ABI_CACHE_TTL_MS 86400000 Contract ABI cache TTL (default 24 h)

Running locally

# Install dependencies
npm ci

# Build all packages
npm run build

# Start the API (production)
npm start

# Or start in watch mode (development)
npm run dev

Create a .env file in packages/api/ (see packages/api/.env.example):

STACKS_CORE_RPC_HOST=localhost
STACKS_CORE_RPC_PORT=20443
STACKS_CORE_RPC_AUTH_TOKEN=your-auth-token

Running with Docker

docker build -t stacks-mesh-api .

docker run -p 3000:3000 \
  -e STACKS_CORE_RPC_HOST=host.docker.internal \
  -e STACKS_CORE_RPC_PORT=20443 \
  -e STACKS_CORE_RPC_AUTH_TOKEN=your-auth-token \
  stacks-mesh-api

The API will be available at http://localhost:3000.

API endpoints

All endpoints accept POST requests with a JSON body. Every request must include a network_identifier:

{
  "network_identifier": { "blockchain": "stacks", "network": "mainnet" }
}

Network

Endpoint Description
/network/list List supported networks
/network/status Current block, sync status, and peers
/network/options Mesh spec version, supported operations, and errors

Data

Endpoint Description
/block Get a block by hash or height
/block/transaction Get a specific transaction within a block
/account/balance Get STX balance, nonce, and lock info for an address

Construction

Endpoint Description
/construction/derive Derive an address from a public key
/construction/preprocess Parse operations into construction options
/construction/metadata Fetch nonce, balance, and suggested fee
/construction/payloads Build unsigned transaction and signing payloads
/construction/combine Attach signatures to an unsigned transaction
/construction/parse Decode a signed or unsigned transaction into operations
/construction/hash Compute the hash of a signed transaction
/construction/submit Broadcast a signed transaction

Smart contract

Endpoint Description
/call Read-only contract calls and contract metadata queries

Transaction construction

Transaction construction follows the standard Mesh offline flow:

preprocess ──> metadata ──> payloads ──> [sign offline] ──> combine ──> submit

The API supports three transaction types: STX token transfers, contract calls, and contract deployments.

Example: STX token transfer

1. Preprocess

Declare the transfer intent as a pair of operations (sender debits, recipient credits):

curl -s http://localhost:3000/construction/preprocess -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "testnet" },
  "operations": [
    {
      "operation_identifier": { "index": 0 },
      "type": "token_transfer",
      "account": { "address": "STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6" },
      "amount": { "value": "-1000000", "currency": { "symbol": "STX", "decimals": 6 } },
      "metadata": { "memo": "hello" }
    },
    {
      "operation_identifier": { "index": 1 },
      "type": "token_transfer",
      "account": { "address": "ST11NJTTKGVT6D1HY4NJRVQWMQM7TVAR091EJ8P2Y" },
      "amount": { "value": "1000000", "currency": { "symbol": "STX", "decimals": 6 } },
      "metadata": { "memo": "hello" }
    }
  ]
}'

Returns options (construction parameters) and required_public_keys.

2. Metadata

Fetch the sender's nonce, balance, and a suggested fee:

curl -s http://localhost:3000/construction/metadata -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "testnet" },
  "options": { "...options from preprocess..." },
  "public_keys": [
    { "hex_bytes": "YOUR_PUBLIC_KEY_HEX", "curve_type": "secp256k1" }
  ]
}'

Returns metadata and suggested_fee.

3. Payloads

Build the unsigned transaction. Include a fee operation (negative amount from the sender) plus the original transfer operations:

curl -s http://localhost:3000/construction/payloads -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "testnet" },
  "operations": [
    {
      "operation_identifier": { "index": 0 },
      "type": "fee",
      "account": { "address": "STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6" },
      "amount": { "value": "-200", "currency": { "symbol": "STX", "decimals": 6 } }
    },
    {
      "operation_identifier": { "index": 1 },
      "type": "token_transfer",
      "account": { "address": "STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6" },
      "amount": { "value": "-1000000", "currency": { "symbol": "STX", "decimals": 6 } },
      "metadata": { "memo": "hello" }
    },
    {
      "operation_identifier": { "index": 2 },
      "type": "token_transfer",
      "account": { "address": "ST11NJTTKGVT6D1HY4NJRVQWMQM7TVAR091EJ8P2Y" },
      "amount": { "value": "1000000", "currency": { "symbol": "STX", "decimals": 6 } },
      "metadata": { "memo": "hello" }
    }
  ],
  "metadata": { "...metadata from previous step..." },
  "public_keys": [
    { "hex_bytes": "YOUR_PUBLIC_KEY_HEX", "curve_type": "secp256k1" }
  ]
}'

Returns unsigned_transaction (hex) and payloads (the signing payload with ecdsa_recovery signature type).

4. Sign offline

Sign the payload hex bytes from the previous step using your private key (secp256k1, recoverable ECDSA). This step happens entirely offline.

5. Combine

Attach the signature to the unsigned transaction:

curl -s http://localhost:3000/construction/combine -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "testnet" },
  "unsigned_transaction": "UNSIGNED_TX_HEX",
  "signatures": [
    {
      "signing_payload": { "...payload from step 3..." },
      "public_key": { "hex_bytes": "YOUR_PUBLIC_KEY_HEX", "curve_type": "secp256k1" },
      "signature_type": "ecdsa_recovery",
      "hex_bytes": "SIGNATURE_HEX"
    }
  ]
}'

Returns signed_transaction (hex).

6. Submit

Broadcast the signed transaction to the network:

curl -s http://localhost:3000/construction/submit -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "testnet" },
  "signed_transaction": "SIGNED_TX_HEX"
}'

Returns transaction_identifier with the transaction hash.

Example: contract call

The preprocess step for a contract call uses a single operation:

curl -s http://localhost:3000/construction/preprocess -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "testnet" },
  "operations": [
    {
      "operation_identifier": { "index": 0 },
      "type": "contract_call",
      "account": { "address": "STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6" },
      "metadata": {
        "contract_identifier": "ST000000000000000000002AMW42H.pox-4",
        "function_name": "stack-stx",
        "args": [
          "0x0100000000000000000000000005f5e100",
          "0x0c00000002096861736862797465730200000014b1c0e25ed2ed6e8b2a09adde1b974bea2c92ec050b76657273696f6e020000000100",
          "0x0100000000000000000000000000000064",
          "0x010000000000000000000000000000000c"
        ]
      }
    }
  ]
}'

Function arguments are hex-encoded Clarity values. The rest of the flow (metadata, payloads, sign, combine, submit) is identical to the token transfer example.

Read-only contract calls

The /call endpoint supports several methods for interacting with smart contracts without broadcasting a transaction.

Call a read-only function

curl -s http://localhost:3000/call -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "mainnet" },
  "method": "contract_call_read_only",
  "parameters": {
    "deployer_address": "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9",
    "contract_name": "age000-governance-token",
    "function_name": "get-balance",
    "sender": "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9",
    "arguments": ["0x0516a654a8dfa3ec004870690aca959868fbc4883402"]
  }
}'

Returns a decoded Clarity value:

{
  "idempotent": false,
  "result": {
    "hex": "0x0700000000000000000000000005f5e100",
    "repr": "(ok u100000000)",
    "type": "ResponseOk(uint)"
  }
}

Get a contract's ABI

curl -s http://localhost:3000/call -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "mainnet" },
  "method": "contract_get_interface",
  "parameters": {
    "deployer_address": "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9",
    "contract_name": "age000-governance-token"
  }
}'

Get a contract's source code

curl -s http://localhost:3000/call -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "mainnet" },
  "method": "contract_get_source",
  "parameters": {
    "deployer_address": "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9",
    "contract_name": "age000-governance-token"
  }
}'

Read a data variable

curl -s http://localhost:3000/call -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "mainnet" },
  "method": "contract_get_data_var",
  "parameters": {
    "deployer_address": "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9",
    "contract_name": "age000-governance-token",
    "var_name": "token-uri"
  }
}'

Read a map entry

curl -s http://localhost:3000/call -H 'Content-Type: application/json' -d '{
  "network_identifier": { "blockchain": "stacks", "network": "mainnet" },
  "method": "contract_get_map_entry",
  "parameters": {
    "deployer_address": "SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9",
    "contract_name": "age000-governance-token",
    "map_name": "token-balances",
    "key": "0x0516a654a8dfa3ec004870690aca959868fbc4883402"
  }
}'

Supported /call methods

Method Description
contract_call_read_only Invoke a read-only contract function
contract_get_interface Get the contract ABI (functions, variables, maps, tokens)
contract_get_source Get the contract Clarity source code
contract_get_constant_val Get the value of a defined constant
contract_get_data_var Read a define-data-var variable
contract_get_map_entry Look up a define-map entry by key

Operation types

The API recognizes the following operation types when serializing block data:

coinbase, fee, token_transfer, token_mint, token_burn, contract_call, contract_deploy, tenure_change, poison_microblock, stx_lock, contract_log, handle-unlock, stack-stx, stack-increase, stack-extend, delegate-stx, delegate-stack-stx, delegate-stack-increase, delegate-stack-extend, stack-aggregation-commit, stack-aggregation-commit-indexed, stack-aggregation-increase, revoke-delegate-stx

Testing

# Run API unit/integration tests
npm run test:api -w @stacks/mesh-api

# Run construction end-to-end tests (requires Docker)
npm run test:construction -w @stacks/mesh-api

The construction tests spin up a Stacks node in Docker and run the full transaction lifecycle against it using the mesh-cli (Rosetta CLI) validator.

License

MIT

About

A Mesh API (formerly Rosetta API) implementation for the Stacks blockchain

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages