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 & Runnable Examples
Module github.com/calmw/chainpulse; run sdk-go-example/query and webhook_receiver with go run. go.mod replaces to sdk/golang.
Query API: Address Balances
Pass chainId matching the chain where the address was indexed (demo: 968). HMAC signs the full PATH_WITH_QUERY. Timestamps use YYYY-MM-DD HH:mm:ss; Go SDK needs FlexTime (v1.0.2+ or local replace).
cURL Example
curl -X GET 'https://query.chainpulse.cc/v1/addresses/0x0f4b9fC118DC2428745A10970F680ff06b0d5723/balances?chainId=968&consistency=stable&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/0x0f4b9fC118DC2428745A10970F680ff06b0d5723/balances?chainId=968&consistency=stable&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("https://query.chainpulse.cc" + 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 (sdk-go-example/query)
github.com/calmw/chainpulse / sdk-go-example/query// sdk-go-example/query — go.mod replace => ../../sdk/golang
package main
import (
"context"
"fmt"
"log"
"os"
chainpulse "github.com/calmw/chainpulse"
)
func main() {
client := chainpulse.NewClient(
chainpulse.WithQueryBaseURL("https://query.chainpulse.cc"),
chainpulse.WithAPIKey(os.Getenv("CHAINPULSE_API_KEY"), os.Getenv("CHAINPULSE_API_SECRET")),
)
params := chainpulse.QueryParams{
ChainID: 968,
Consistency: "stable",
Limit: 20,
}
balances, err := client.ListAddressBalances(context.Background(), "0x0f4b9fC118DC2428745A10970F680ff06b0d5723", params)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", balances)
}
// CHAINPULSE_CHAIN_ID=968 CHAINPULSE_TX_HASH=0xb9308cad0162f61d29b0fe0f892a83fcd62777f4a99a8c5abaf54eda94c2c131 go run .Runnable Demo
sdk-go-example/query: CHAINPULSE_CHAIN_ID=968 for balances & internal tx; webhook_receiver: ngrok + whsec_ to receive pushes.
Security Boundary
Public Query API is read-only. Webhook verification must use the raw body — re-serialized JSON will fail signature check.
Push Timing
pending is faster but coin excludes internal transfers; use stable for crediting (includes internal_to). pending/stable are mutually exclusive per user.