Usage examples

Learn Chainhook's core functionality through practical examples - predicates, event scopes, reorg handling, and operation modes.

Predicates

Predicates are JSON specifications that tell Chainhook what blockchain events to monitor and how to respond. They follow an if-this-then-that pattern.

stx-transfer-predicate.json
{
"chain": "stacks",
"uuid": "1",
"name": "Monitor STX Transfers",
"version": 1,
"networks": {
"mainnet": {
"if_this": {
"scope": "stx_event",
"actions": ["transfer"]
},
"then_that": {
"http_post": {
"url": "https://api.example.com/stx-transfers",
"authorization_header": "Bearer secret-token"
}
},
"start_block": 100000
}
}
}

This predicate monitors all STX transfer events starting from block 100,000 and sends them to your webhook endpoint.

Predicate components

{
"chain": "bitcoin", // Target blockchain: "bitcoin" or "stacks"
"uuid": "unique-id-123", // Unique identifier for tracking
"name": "My Bitcoin Monitor", // Human-readable name
"version": 1, // Predicate version
"networks": { // Network-specific configurations
"mainnet": { ... },
"testnet": { ... }
}
}

Event scopes

Each blockchain supports different event types. Scopes define what specific events your predicate will match.

Stacks events

contract-call-predicate.json
{
"if_this": {
"scope": "contract_call",
"contract_identifier": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-oracle-v2-3",
"method": "update-price"
}
}

Monitor specific contract function calls. Available Stacks scopes:

  • stx_event - STX transfers, mints, burns
  • contract_call - Smart contract function calls
  • contract_deployment - New contract deployments
  • print_event - Contract print statements
  • ft_event - Fungible token operations
  • nft_event - Non-fungible token operations

Bitcoin events

bitcoin-ordinals-predicate.json
{
"if_this": {
"scope": "ordinals_protocol",
"operation": "inscription_feed"
}
}

Track Bitcoin ordinal inscriptions. Available Bitcoin scopes:

  • p2pkh, p2sh, p2wpkh, p2tr - Address types
  • ordinals_protocol - Ordinal inscriptions
  • stacks_protocol - Stacks-specific Bitcoin operations

Action handlers

Define how Chainhook responds when events match your predicate criteria.

Webhook delivery

webhook-config.json
{
"then_that": {
"http_post": {
"url": "https://api.myapp.com/events",
"authorization_header": "Bearer ${WEBHOOK_SECRET}"
}
}
}

Chainhook POSTs matching events to your endpoint with the authorization header.

File output

file-output-config.json
{
"then_that": {
"file_append": {
"path": "/data/blockchain-events.jsonl"
}
}
}

Append events to a local file, one JSON object per line.

Blockchain reorganizations

Chainhook automatically handles blockchain reorganizations (reorgs) by sending both rollback and apply events.

reorg-event.json
{
"apply": [
{
"block_identifier": {
"index": 792101,
"hash": "0x123..."
},
"transactions": [
// New canonical chain transactions
]
}
],
"rollback": [
{
"block_identifier": {
"index": 792100,
"hash": "0x456..."
},
"transactions": [
// Transactions to rollback
]
}
]
}

Your application must handle both event types to maintain data consistency during reorgs.

Handling reorg events

webhook-handler.ts
app.post('/chainhook-events', (req, res) => {
const { apply, rollback } = req.body;
// First, rollback orphaned transactions
if (rollback) {
for (const block of rollback) {
await removeTransactions(block.transactions);
}
}
// Then apply new canonical transactions
if (apply) {
for (const block of apply) {
await processTransactions(block.transactions);
}
}
res.status(200).send('OK');
});

Operation modes

Chainhook operates in two primary modes depending on your use case.

Scanning mode

Analyze historical blockchain data by scanning archived blocks:

Terminal
$
chainhook predicates scan my-predicate.json --mainnet

Use scanning mode for:

  • Testing predicates before deployment
  • Analyzing past blockchain events
  • Backfilling historical data

Service mode

Monitor live blockchain events in real-time:

Terminal
$
chainhook service start --config-path=config.toml
config.toml
[http_api]
http_port = 20456
database_uri = "redis://localhost:6379"
[network]
mode = "mainnet"
bitcoind_rpc_url = "http://localhost:8332"
stacks_node_rpc_url = "http://localhost:20443"

Service mode maintains persistent connections to blockchain nodes and processes new blocks as they arrive.

Network configuration

Configure predicates differently for each network environment:

multi-network-predicate.json
{
"networks": {
"mainnet": {
"start_block": 100000,
"if_this": {
"scope": "stx_event",
"actions": ["transfer", "mint"]
}
},
"testnet": {
"start_block": 1,
"decode_clarity_values": true,
"include_proof": true,
"if_this": {
"scope": "print_event"
}
}
}
}

Configuration options

{
"start_block": 100000, // Begin scanning from this block
"end_block": 200000, // Stop at this block (optional)
"expire_after_occurrence": 5000, // Stop after N matches
"decode_clarity_values": true, // Decode Clarity data types
"include_proof": false, // Include merkle proofs
"include_contract_abi": true // Include contract interfaces
}

Further reading