Build a Whale Alert Bot with the OpenScan.AI API
In this tutorial you’ll build a small Node.js bot that watches an address on XDC Network and posts an alert to a webhook (Slack, Discord, or your own service) whenever it receives a large transfer. You’ll use the public REST API at xdcscan.io — no signup required, and the whole thing is under 100 lines.
What you’ll learn
- Querying an address’s transaction history with
/api/v2/addresses/{hash}/transactions - Filtering and deduplicating results
- Posting alerts to an incoming webhook
- When to switch from polling to the watchlist/webhook service
Prerequisites
- Node.js 18+ (for built-in
fetch) - A webhook URL (Slack and Discord both offer incoming webhooks)
- The address you want to watch
Step 1: Fetch recent transactions
The API returns an address’s transactions newest-first:
const WATCHED = "0x1234567890abcdef1234567890abcdef12345678";
const res = await fetch( `https://xdcscan.io/api/v2/addresses/${WATCHED}/transactions`,);const { items } = await res.json();
console.log(items[0].hash, items[0].value);Each item includes hash, from, to, value (in wei), timestamp, and status.
Step 2: Filter for large incoming transfers
We only care about successful transactions to the watched address above a threshold:
const THRESHOLD_XDC = 100_000;
function isWhaleTransfer(tx) { const amount = Number(tx.value) / 1e18; return ( tx.status === "ok" && tx.to?.hash?.toLowerCase() === WATCHED.toLowerCase() && amount >= THRESHOLD_XDC );}Step 3: Deduplicate with a seen-set
Polling returns overlapping windows, so track hashes you’ve already alerted on:
const seen = new Set();
async function poll() { const res = await fetch( `https://xdcscan.io/api/v2/addresses/${WATCHED}/transactions`, ); const { items } = await res.json();
for (const tx of items) { if (seen.has(tx.hash) || !isWhaleTransfer(tx)) continue; seen.add(tx.hash); await alert(tx); }}Step 4: Post the alert
const WEBHOOK = process.env.ALERT_WEBHOOK_URL;
async function alert(tx) { const amount = (Number(tx.value) / 1e18).toLocaleString(); await fetch(WEBHOOK, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: `🐋 Whale alert: ${amount} XDC received\n` + `From: ${tx.from.hash}\n` + `Tx: https://xdcscan.io/tx/${tx.hash}`, }), });}Step 5: Run it on an interval
setInterval(() => poll().catch(console.error), 15_000);poll().catch(console.error);Run with:
ALERT_WEBHOOK_URL="https://hooks.slack.com/services/..." node whale-alert.jsStep 6: Harden it (optional)
- Seed the seen-set on startup: alert only on transactions newer than the bot’s start time, or pre-mark the first page as seen.
- Handle 429s: if you poll faster, add an API key and back off on rate-limit responses — see API Keys & Rate Limits.
- Follow token transfers too:
/api/v2/addresses/{hash}/token-transfers?type=ERC-20catches whale moves in stablecoins, not just native XDC.
Step 7: Go serverless — use watchlist webhooks instead
Polling is fine for a hobby bot, but production alerting shouldn’t run a loop on your laptop. Add the address to a watchlist with webhook notifications and OpenScan.AI pushes each matching transaction to your endpoint as it’s indexed:
curl -X POST https://xdcscan.io/account/api/v1/user/watchlist \ -H "Authorization: Bearer $OPENSCAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "address_hash": "0x1234567890abcdef1234567890abcdef12345678", "name": "Whale watch", "notification_settings": { "native": { "incoming": true } }, "notification_methods": { "webhook": true } }'Your webhook receiver then just verifies the signature and reposts — see Alerts & Webhooks for the payload format and HMAC verification.
Next steps
- SDK Examples — portfolio tracker, CSV exports
- API Reference — every endpoint
- Account API — watchlists, tags, and keys