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.
4 steps
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.
Open GitHub
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())
package 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.