Query + Webhook Demo
From active queries to real-time push — a complete integration example
API Key signed queries, Webhook setup, receiver signature verification, and idempotent event handling — all on one page. Copy the sample code to integrate on-chain transactions, balances, and contract events into your system.
HMAC SigningGo SDKWebhook Verificationstable / pending
Integration Roadmap
Query for active lookups, Webhook for push on match.
1
Create API Key
Generate key/secret for HMAC signing
2
Signed Query Calls
Query transactions, balances, internal transfers, and events
3
Configure Webhook URL
Select coin/token/contract event types
4
Verify & Process Events
Verify signature, idempotent storage by eventId
Create API Key
Create an API Key in your profile. Save key and secret — secret is used locally for signing only, never sent as a plain header.
Call Query API
Use HMAC signing to query indexed transactions, balances, internal transfers, and contract events.
Configure Webhook
Set receiver URL and event types, then import wallet, Token, or contract watch targets.
Verify & Store
Receiver validates X-Bot-Signature, then processes idempotently by eventId.
Go SDK Repository
The SDK will be published to GitHub; Go examples in this demo will use that module directly.
Query API: Address Balances
Query service uses API Key + API Secret for HMAC signing. Request path and query string must be included in the signature.
cURL Example
curl -X GET 'http://localhost:5001/v1/addresses/0x7C76578494e1e7D1a7ac70247a7fb73b01CBfec5/balances?chainId=968&limit=20' \
-H 'X-API-Key: ck_live_xxx' \
-H 'X-API-Timestamp: 1779105954' \
-H 'X-API-Nonce: 35a6a5094a1784b4dad9d8ff' \
-H 'X-API-Signature: sha256=<hmac_signature>'Node.js Signed Request
import crypto from "node:crypto"
const apiKey = process.env.CHAINPULSE_API_KEY!
const apiSecret = process.env.CHAINPULSE_API_SECRET!
const method = "GET"
const path = "/v1/addresses/0x7C76578494e1e7D1a7ac70247a7fb73b01CBfec5/balances?chainId=968&limit=20"
const timestamp = Math.floor(Date.now() / 1000).toString()
const nonce = crypto.randomBytes(12).toString("hex")
const signingString = [method, path, timestamp, nonce].join("\n")
const signature = "sha256=" + crypto
.createHmac("sha256", apiSecret)
.update(signingString)
.digest("hex")
const response = await fetch("http://localhost:5001" + path, {
headers: {
"X-API-Key": apiKey,
"X-API-Timestamp": timestamp,
"X-API-Nonce": nonce,
"X-API-Signature": signature,
},
})
console.log(await response.json())Go SDK Query
github.com/calmw/blockflowpackage main
import (
"context"
"fmt"
blockflow "github.com/calmw/blockflow"
)
func main() {
client := blockflow.NewClient(
blockflow.WithQueryBaseURL("http://localhost:5001"),
blockflow.WithAPIKey("ck_live_xxx", "sk_live_xxx"),
)
balances, err := client.ListAddressBalances(
context.Background(),
"0x7C76578494e1e7D1a7ac70247a7fb73b01CBfec5",
)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", balances)
}Local Query Testing
query/signature_test.go in the backend repo generates curl commands and makes real requests to the local Query service.
Security Boundary
Public Query API is read-only; balance refresh is now internal and requires QUERY_INTERNAL_TOKEN.
Push Timing
Both pending and stable push coin/token/contract events; pending is faster, stable includes internal transfers and is suitable for crediting.