Alchemy Webhooks & Events (Notify API)
Overview
Alchemy Notify provides real-time push notifications for on-chain events. Instead of polling, receive webhook callbacks for wallet activity, mined transactions, dropped transactions, and smart contract events.
Webhook Types
| Type | Trigger | Use Case | |------|---------|----------| | Address Activity | ETH/token transfer to/from address | Wallet notifications | | Mined Transaction | Transaction confirmed on-chain | Payment confirmation | | Dropped Transaction | Transaction removed from mempool | Failed tx alerting | | NFT Activity | NFT transfer events | Marketplace notifications | | Custom Webhook | GraphQL-defined filter | Complex event tracking |
Instructions
Step 1: Create Webhook via Dashboard or API
# Create Address Activity webhook via Alchemy API
curl -X POST "https://dashboard.alchemy.com/api/create-webhook" \
-H "X-Alchemy-Token: ${ALCHEMY_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"network": "ETH_MAINNET",
"webhook_type": "ADDRESS_ACTIVITY",
"webhook_url": "https://your-app.com/webhooks/alchemy",
"addresses": [
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
]
}'
Step 2: Webhook Handler with Signature Verification
// src/webhooks/alchemy-handler.ts
import express from 'express';
import crypto from 'crypto';
const router = express.Router();
router.post('/webhooks/alchemy',
express.raw({ type: 'application/json' }),
async (req, res) => {
// Verify webhook signature
const signature = req.headers['x-alchemy-signature'] as string;
if (!verifySignature(req.body.toString(), signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body.toString());
await processAlchemyEvent(event);
res.status(200).json({ ok: true });
}
);
function verifySignature(body: string, signature: string): boolean {
const signingKey = process.env.ALCHEMY_WEBHOOK_SIGNING_KEY!;
const hmac = crypto.createHmac('sha256', signingKey);
hmac.update(body, 'utf8');
const digest = hmac.digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}
Step 3: Event Router
// src/webhooks/event-router.ts
interface AlchemyWebhookEvent {
webhookId: string;
id: string;
createdAt: string;
type: 'ADDRESS_ACTIVITY' | 'MINED_TRANSACTION' | 'DROPPED_TRANSACTION' | 'NFT_ACTIVITY';
event: {
network: string;
activity: Array<{
fromAddress: string;
toAddress: string;
value: number;
asset: string;
category: 'external' | 'internal' | 'erc20' | 'erc721' | 'erc1155';
hash: string;
blockNum: string;
}>;
};
}
async function processAlchemyEvent(event: AlchemyWebhookEvent): Promise<void> {
switch (event.type) {
case 'ADDRESS_ACTIVITY':
for (const activity of event.event.activity) {
console.log(`${activity.category} transfer: ${activity.value} ${activity.asset}`);
console.log(` From: ${activity.fromAddress}`);
console.log(` To: ${activity.toAddress}`);
console.log(` Tx: ${activity.hash}`);
// Trigger application logic (e.g., update balance, send notification)
}
break;
case 'MINED_TRANSACTION':
console.log('Transaction mined:', event.event);
break;
case 'DROPPED_TRANSACTION':
console.log('Transaction dropped:', event.event);
// Alert user their transaction was dropped
break;
case 'NFT_ACTIVITY':
for (const activity of event.event.activity) {
console.log(`NFT transfer: ${activity.asset} #${activity.value}`);
}
break;
}
}
Step 4: Programmatic Webhook Management
// src/webhooks/manage-webhooks.ts
import { Alchemy, Network, WebhookType } from 'alchemy-sdk';
const alchemy = new Alchemy({
apiKey: process.env.ALCHEMY_API_KEY,
network: Network.ETH_MAINNET,
authToken: process.env.ALCHEMY_AUTH_TOKEN, // Required for Notify API
});
async function setupAddressWebhook(addresses: string[], webhookUrl: string) {
const webhook = await alchemy.notify.createWebhook(
webhookUrl,
WebhookType.ADDRESS_ACTIVITY,
{ addresses, network: Network.ETH_MAINNET }
);
console.log(`Webhook created: ${webhook.id}`);
return webhook;
}
async function listWebhooks() {
const webhooks = await alchemy.notify.getAllWebhooks();
for (const wh of webhooks.webhooks) {
console.log(`${wh.id}: ${wh.webhookType} → ${wh.webhookUrl} (${wh.isActive ? 'active' : 'inactive'})`);
}
}
async function addAddressToWebhook(webhookId: string, newAddresses: string[]) {
await alchemy.notify.updateWebhook(webhookId, {
addAddresses: newAddresses,
});
}
Output
- Address Activity webhook for wallet monitoring
- HMAC signature verification for webhook security
- Event router handling all Alchemy webhook types
- Programmatic webhook management via Notify API
Error Handling
| Issue | Cause | Solution | |-------|-------|----------| | Invalid signature | Wrong signing key | Copy from Alchemy webhook details page | | Missing events | Webhook URL not reachable | Ensure HTTPS endpoint is publicly accessible | | Duplicate events | No idempotency | Track webhook event IDs |
Resources
Next Steps
For performance optimization, see alchemy-performance-tuning.