.md

Listen for Stacks contract events

A contract announces what happened by printing an event. A webhook posts each print to a URL you run, as the block lands. One key, one call:

$curl -X POST "$SECONDLAYER_API_URL/api/webhooks" \
-H "Authorization: Bearer sk-sl_…" \
-H "Content-Type: application/json" \
-d '{
"name": "sbtc-withdrawals",
"url": "https://my-app.com/webhooks/sbtc",
"triggers": [{
"type": "print_event",
"contractId": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry",
"topic": "withdrawal-create"
}]
}'
201response.jsonjson
{
"webhook": {
"id": "65ea1ed2-7b2d-4255-ae82-347fbc1023b3",
"name": "sbtc-withdrawals",
"status": "active",
"kind": "chain",
"format": "standard-webhooks",
"url": "https://my-app.com/webhooks/sbtc",
"createdAt": "2026-10-28T17:59:19.072Z",
"triggers": [
{
"type": "print_event",
"topic": "withdrawal-create",
"contractId": "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry"
}
],
},
"signingSecret": "…"
}

The signing secret comes back once, so store it. Every delivery carries a signature you check with it: Verify the signature.

The trigger above matches one print topic. Match other prints, or other events:

To matchUse
Other keys in the printwhere (Print fields)
Calls instead of printstrigger.contractCall (Triggers)

Each delivery is one signed POST. The print arrives as data.event.data.value, already parsed from Clarity: Event shapes.

A webhook starts at the chain tip and never backfills. To re-deliver a block range over it, replay. To read past prints once and resume from a block, page Streams with a cursor.

Hosted webhooks run on your stack, $5 a month at the minimum (What it costs). Triggers and the create call: Create a webhook.

Edit on GitHub