Helius Webhooks Tutorial: Stream Solana Events Live.

Okay, first off - go to helius.dev, sign up for a free account, grab your API, and hit the Webhooks tab. Boom. Add a new one, pick mainnet, slap in a dummy URL like their built in logger, add Tensor's swap program address (it's TsrB2hGfpa4vn7k64wC8V9E1eTq8wVCsP99EiUq7vB), set it to NFT sales. Create it. Now watch live Tensor NFT sales ping in real time. Why? 'Cause Helius parses hundreds of tx types out of the box. No server needed yet. Pretty much instant gratification.

In my experience, this tricks you into believing it's that easy. And it is. But stick around - we'll build the real deal.

Why Bother with Helius Webhooks Anyway?

Look, Solana's fast. Like, 50k TPS fast. Polling RPCs? You'll drown in rate limits and lag. Webhooks? Helius shoves events straight to your endpoint the second they happen. NFT sale? Token transfer? Wallet move? Ping. Fee's tiny too - think ~0.000005 SOL per tx in the payload.

The thing is, raw Solana txns are a mess. Base64 blobs, inner instructions everywhere. Helius "enhances" 'em - parses out the good stuff like feePayer, signature, tokenAmounts with decimals. Sound familiar if you've decoded a few yourself?

Honestly, I usually start here for any live app. Bots, alerts, dashboards. Scales to 100k addresses per hook. Free tier's generous too.

Get Your Free Setup in 2 Minutes Flat

  1. Head to helius.dev. Sign up. Dashboard spits out your API. Copy it.
  2. Click Webhooks in the nav. Add New Webhook.
  3. Network: Mainnet (or devnet for testing).
  4. Webhook URL: Use their logger first - https://logger.helius.dev/your webhook id or whatever it gives ya.
  5. Transaction types: Pick NFT_SALE, TRANSFER, or ANY for chaos.
  6. Account addresses: Drop one wallet or program ID. Like a hot wallet: 1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix.
  7. Webhook type: enhanced. Trust me.
  8. Hit create. Done. Check the logs tab - events flowing if there's action.

What's next? Test fire. Helius has a Send Test button. Fires fake data. Your endpoint must respond 200 OK quick, or retries fail after 3 tries. Miss that? Events drop. Brutal but fair.

Via API If You're Feeling Fancy

Dashboard caps at 25 addresses. Need more? Curl it.

curl -X POST 'https://api mainnet.helius rpc.com/v0/webhooks' \
-H 'Content Type: application/json' \
-d '{ "accountAddresses": ["YourWalletHere"], "transactionTypes": ["ANY"], "webhookURL": "https://your server.com/webhook", "authHeader": {"": "shh secret"}, "webhookType": "enhanced"
}' \
-H 'Authorization: Bearer YOURAPIKEY'

Swap in your deets. Fire. Webhook ID comes back. Save it - you'll update later.

Build a Dead Simple Endpoint to Catch 'Em

Now, you need somewhere to land these POSTs. I usually spin up Node/Express 'cause it's braindead easy. Or Cloudflare Workers if you're serverless and cheap.

Here's Express. Install nothing fancy - just express and body parser.

const express = require('express');
const app = express();
app.use(express.json()); app.post('/webhook', (req, res) => { console.log('Boom, event:', req.body); req.body.forEach(event => { if (event.type === 'NFT_SALE') { console.log(Sold ${event.tokenTransfers.tokenAmount.asDecimal} for ${event.nativeTransfers.tokenAmount.asDecimal} SOL); } }); res.status(200).send('OK'); // Critical!
}); app.listen(3000, () => console.log('Listening on 3000'));

Deploy to Render, Vercel, whatever. Ngrok it for local testing: ngrok http 3000. Grab the https URL. Plug into Helius. Test. Watch console explode with live txns.

Potential gotcha: Timeouts. Helius waits 10s max. Keep it snappy - no heavy DB writes in the handler. Offload to queues.

Real Example: NFT Sales on Tensor Live

Tensor's program: TsrB2hGfpa4vn7k64wC8V9E1eTq8wVCsP99EiUq7vB. Set webhook to NFT_SALE + that address. Payload looks like this (trimmed):

{ "signature": "5xTxTx..", "type": "NFT_SALE", "source": "TENSOR", "tokenTransfers": [ { "tokenAmount": {"decimals": 0, "tokenAmount": "1"}, "tokenAccount": "25DTUAd1roBFoUQaxJQByL6Qy2cKQCBp4bK9sgfy9UiM", "userAccount": "1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix" } ], "nativeTransfers": [{"tokenAmount": {"asDecimal": "420.69"}}], "fee": 5000, "slot": 1234567, "timestamp": 1234567890000
}

Why does this matter? Parse nativeTransfers for SOL price. tokenTransfers for NFT deets. Build a Discord bot? Slack alert? Easy.

In my experience, start with enhanced type. Raw's cheaper but you decode yourself. Enhanced? Parsed gold.

Scale It: Track a Whole Collection Without Carpal Tunnel

  • Manually? Up to 25 in dashboard. Lame for big drops.
  • API? 100k addresses max. But listing 'em sucks.
  • Hack: Use Helius SDK for snapshot. Get all mints from a creator.

Okay, Node script time. Install @helius labs/helius sdk.

const { Helius } = require('helius sdk');
const fs = require('fs'); const helius = new Helius('YOURAPIKEY');
const creator = 'CREATORADDRESSHERE'; // e.g. Mad Lads dude async function snapshot() { const nfts = await helius.rpc.getAssetsByCreator({ creatorAddress: creator, page: 1 }); const addresses = nfts.items.map(nft => nft.id); fs.writeFileSync('addresses.json', JSON.stringify(addresses)); console.log(Snapped ${addresses.length} mints);
}
snapshot();

Run it. Spits addresses.json. Now update webhook:

const webhookId = 'YOURWEBHOOKID';
const addresses = JSON.parse(fs.readFileSync('addresses.json')); await helius.rpc.updateWebhook(webhookId, { accountAddresses: addresses, transactionTypes: ['NFTSALE', 'NFTBID']
});

Now every sale/bid in that collection pings you. Test with Helius' test button - it'll simulate.

Cloudflare Worker for Telegram Alerts (Zero Cost)

Want free hosting? Workers. Acts as middleman: Helius → Worker → Telegram.

  1. Create bot at Telegram: @BotFather. Grab token.
  2. Add bot to channel. Get chat ID: Forward msg to @userinfobot.
  3. New Worker. Paste this:
export default { async fetch(request, env) { if (request.method === 'POST') { const events = await request.json(); for (const event of events) { if (event.type === 'TRANSFER') { await fetch(https://api.telegram.org/bot${BOTTOKEN}/sendMessage, { method: 'POST', headers: { 'Content Type': 'application/json' }, body: JSON.stringify({ chatid: CHAT_ID, text: Transfer! ${event.tokenTransfers.userAccount} → ${event.tokenTransfers.userAccount} ${event.tokenTransfers.tokenAmount.asDecimal} }) }); } } } return new Response('OK', { status: 200 }); }
};

Env vars: BOTTOKEN, CHATHID. Deploy. Copy URL. Set as webhook target in Helius. Watch Telegram light up on real txns.

Issue? Workers cold start ms. Fine for Solana speed. But add authHeader in Helius for security: {"": "your secret"}. Check it in worker.

What the Payload Really Looks Like (Break It Down)

What It MeansExample
signatureTx ID. Track it.5xTxTx..abc
typeEvent kind.NFT_SALE
feeTx fee in lamports (1 SOL = 1e9).5000 (~0.000005 SOL)
timestampUnix ms. Convert for humans.1673445241000
tokenTransfersArray of moves. Has asDecimal in enhanced.-1 NFT from seller
nativeTransfersSOL moves.420.69 SOL payment
accountDataChanged accounts.Array of deltas

Pro tip: Always check err: null. Failed txns still webhook if subscribed.

Troubleshooting the Annoying Stuff

Hitting walls? Common ones.

  • No events? Check logs in dashboard. Wrong network? Addresses case sensitive (all lowercase). Txn types match? Test button.
  • Duplicates? Helius dedupes, but slots can replay. Track signatures.
  • Rate limited? Free tier: 1000 webhooks/min? Nah, generous. But spam tests = ban. Chill.
  • Payload too big? Big collections = fat batches. Chunk process.
  • Offline endpoint? Helius retries 3x over 1min. Then drops. Add dead letter queue.

Discord's gold: discord.gg/helius. Ask there. They're quick.

Level Up: WebSockets If Webhooks Ain't Enough

Webhooks fire on events. Need everything streaming? WS.

const ws = new WebSocket('wss://mainnet.helius rpc.com/?api=YOUR_KEY');
ws.on('open', () => { ws.send(JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'subscribe', params: [{ account: ['YourWallet'] }] }));
});
ws.on('message', data => console.log(JSON.parse(data)));

But for most? Webhooks. Push, not pull.

Alerts for Your Wallet - Personal Touch

Say you're watching your own bag. Add your wallet address. Set types: SWAP, TRANSFER. Endpoint emails ya? Texts? Boom, notified instantly. Better than Phantom alerts.

I usually filter payload server side. Like, ignore dust: if tokenAmount.asDecimal < 0.01, skip. Clean noise.

One more: Update webhooks anytime. Same endpoint: PATCH /v0/webhooks/{id}. Add/remove addresses dynamically. Power move for dashboards.