How to Set Up Automated Solana Dip Buying with Webhooks — No Polling Required (2026)
Stop burning API calls with polling loops. Learn how to set up webhook-based dip buying on Solana using MadeOnSol's price alert API — sub-second detection, HMAC-verified delivery, and automatic recovery tracking with full Node.js code.
MadeOnSol·· 11 min read
Disclosure: This article contains affiliate links. If you sign up through them, MadeOnSol may earn a commission at no extra cost to you. This never affects our rankings, ratings, or reviews.
Building a product on Solana data?
Skip the Geyser pipeline — embed KOL flow, deployer reputation, and the all-DEX firehose over REST, WebSocket, or webhooks. The Business tier (€400/mo) is the self-serve embed license at 500k calls/day — Enterprise adds white-label & redistribution.
Once the signature checks out, execute a Jupiter swap:
async function executeDipBuy(tokenMint: string, dropPct: number) {
// Scale position size by drop severity
const baseLamports = 100_000_000; // 0.1 SOL
const multiplier = dropPct > 40 ? 3 : dropPct > 30 ? 2 : 1;
const amount = (baseLamports * multiplier).toString();
const quoteUrl = new URL("https://quote-api.jup.ag/v6/quote");
quoteUrl.searchParams.set("inputMint", "So11111111111111111111111111111111111111112");
quoteUrl.searchParams.set("outputMint", tokenMint);
quoteUrl.searchParams.set("amount", amount);
quoteUrl.searchParams.set("slippageBps", "800"); // wider slippage for dip conditions
const quote = await fetch(quoteUrl.toString()).then(r => r.json());
// ... sign and send via @solana/web3.js (see the full code below)
}
Set slippage higher than normal during dips. Liquidity thins out during sharp drops, and tight slippage causes failed transactions right when execution matters most. For the complete signing-and-sending flow and a full runnable bot, see our walkthrough on building a Solana dip-buying bot with sub-second price alerts.
Recovery Webhooks
If you set recovery_pct when creating the alert, the system tracks the lowest MC after the dip fires and sends a price_alert:recovery event when the token bounces by that percentage from the bottom. The recovery payload includes dip_low_mc_usd — the absolute trough — so you can calculate exactly how much of the bounce you captured.
Recovery events serve two purposes: they can trigger profit-taking logic automatically, and they give you hard data on which dip buys actually bounced versus which ones kept bleeding. The same dip-and-recovery webhooks are the backbone of a fuller monitoring setup — our guide to building a Solana portfolio alert system for price drops, KOL exits, and recovery signals wires them into a complete alerting stack.
Polling vs. Webhooks: The Numbers
For a single token watched over 24 hours:
Metric
Polling (5s interval)
Webhook
API calls
17,280
1 (create alert) + 1-2 (dip/recovery)
Detection latency
0-5 seconds
Sub-second (250ms tick)
Server compute
Always running
Idle until event
Rate limit pressure
High
None
At 20 tokens, polling generates 345,600 calls per day. Webhooks generate 20 creation calls and a handful of event deliveries. The architecture difference is not marginal — it is orders of magnitude.
Tools mentioned
Compare features and read reviews.
Live health scores, average ratings, and direct links on MadeOnSol.
MadeOnSol isn't an RPC or another generic token API — it's Solana memecoin intelligence that's painful to build in-house, pulled from dual-region gRPC shred streams: sub-second from the on-chain event to your app.
Signals you'd otherwise build
KOL & smart-money flow from 1,000+ labeled wallets, deployer reputation, coordination clusters, linked-wallet entity resolution, and an all-DEX firehose.
Embed it in your product
The Business tier (€400/mo, self-serve) licenses you to display MadeOnSol data inside your own product — 500k calls/day, 10 WS + 5 firehose connections. Enterprise above adds white-label & redistribution rights and custom endpoints.
Evaluate first, commit later
Test everything on a free ULTRA key — no commitment. If it fits, we scope volume or white-label pricing.
Most automated dip-buying setups on Solana use the same basic pattern: poll a price endpoint every few seconds, compare the result to a threshold, and buy when the price drops far enough. It works, but it is a fundamentally wasteful architecture with real costs that scale as you add tokens.
Polling /token in a loop means 720 API calls per hour at a 5-second interval — per token. Track 20 tokens and you are making 14,400 requests per hour. That burns through rate limits, adds latency (you only detect dips at your poll interval, not when they happen), and keeps a process running 24/7 consuming compute for nothing most of the time.
Webhooks invert this. Instead of asking "has the price dropped?" every 5 seconds, you tell the API once what to watch for and it pushes a notification the instant your condition triggers. Zero wasted calls. Sub-second detection. Your server sits idle until it matters.
The Trade-offs, Stated Plainly
Webhooks are not strictly better than polling in every dimension — they make a different set of trade-offs, and it is worth being explicit about them before you commit:
Latency. Polling detects a dip at best one poll interval late. A webhook detects it at the source, on the same tick the price actually moved. For dip buying, where the window to fill at a good price is short, this is the difference that matters most.
Cost and rate limits. Polling cost scales linearly with both the number of tokens and the poll frequency. Webhook cost is essentially fixed — one create call per alert plus a handful of deliveries. You can watch hundreds of tokens without touching your rate limit.
Reliability. This is where polling has an edge. A polling loop is self-correcting — miss a tick and the next one still reads current state. A webhook is fire-and-forget; if your endpoint is down when the event fires, the delivery can be missed. The fix is operational: keep your receiver highly available, return 200 quickly, and treat the recovery event as a backstop rather than assuming every dip event lands.
Infrastructure. Polling runs anywhere. Webhooks require a publicly reachable HTTPS endpoint, which is a real constraint for local scripts (addressed at the end of this post).
For automated dip buying specifically, the latency and cost advantages dominate, which is why the webhook architecture is the right default here.
How the Webhook Architecture Works
MadeOnSol's price alert system evaluates token market caps inside the mc-tracker publish loop at roughly 250ms intervals. When you create a price alert via the API, you define a token, a drop percentage threshold, and a webhook URL. The system captures the token's current market cap as the baseline.
From that point, every mc-tracker tick checks your alert condition. When the market cap falls below , the system fires an HTTP POST to your webhook URL within milliseconds.
baseline * (1 - drop_pct / 100)
The webhook payload includes everything you need to act:
Your server receives this, verifies the HMAC signature, and executes whatever logic you want — a Jupiter swap, a Telegram notification, a database log, or all three.
Setting Up the Alert
Install the SDK and create an alert that watches for a 25% dip:
npm install madeonsol express
import MadeOnSol from "madeonsol";
const client = new MadeOnSol({ apiKey: process.env.MADEONSOL_API_KEY! });
const alert = await client.priceAlerts.create({
token_mint: "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr",
drop_pct: 25,
recovery_pct: 15,
name: "Auto dip buy — WIF",
delivery_mode: "webhook",
webhook_url: "https://your-server.com/webhook/dip",
});
// Store this — shown once only
console.log("Webhook secret:", alert.webhook_secret);
The webhook_secret is returned on creation and never shown again. Every payload is signed with HMAC-SHA256 using this secret. If you lose it, delete the alert and create a new one.
A few of the parameters deserve explanation, because they shape when and how often the alert fires. drop_pct is the threshold relative to the baseline captured at creation time — set it to the move size that is actually meaningful for the token, not an arbitrary round number. A token that routinely swings 20% intraday will spam you at drop_pct: 10. The recovery_pct parameter is optional and opts you into the recovery tracking described later; omit it if you only care about the dip. The delivery_mode of webhook is what makes the system push to your URL — switching it to the WebSocket mode is the escape hatch for environments without a public endpoint.
Building the Webhook Receiver
The receiver is a standard Express server that verifies the signature before acting on any payload:
import express from "express";
import crypto from "crypto";
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!;
function verifySignature(body: string, timestamp: string, signature: string): boolean {
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(`${timestamp}.${body}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
app.post("/webhook/dip", async (req, res) => {
const rawBody = JSON.stringify(req.body);
const timestamp = req.headers["x-madeonsol-timestamp"] as string;
const signature = req.headers["x-madeonsol-signature"] as string;
if (!timestamp || !signature || !verifySignature(rawBody, timestamp, signature)) {
return res.status(401).send("Invalid signature");
}
const { event, token_mint, drop_pct_actual, current_mc_usd } = req.body;
if (event === "price_alert:dip") {
console.log(`DIP: ${token_mint} dropped ${drop_pct_actual.toFixed(1)}% — MC now $${current_mc_usd}`);
// Execute buy logic here
}
if (event === "price_alert:recovery") {
console.log(`RECOVERY: ${token_mint} bounced back — MC now $${current_mc_usd}`);
// Take profit or log
}
res.status(200).send("OK");
});
app.listen(4000, () => console.log("Webhook receiver running on :4000"));
The HMAC verification is not optional. Without it, anyone who discovers your webhook URL can send fake dip events and trigger buys on arbitrary tokens. Always use timingSafeEqual to prevent timing attacks on the signature comparison.
What the verification step actually proves is twofold: that the payload was produced by someone holding your webhook_secret (authenticity), and that it has not been altered in transit (integrity). The signature is computed over ${timestamp}.${body} rather than the body alone, which binds the timestamp into the signed material — that pairing is what lets you optionally reject stale or replayed deliveries by checking that the timestamp is recent before trusting the payload. The reason timingSafeEqual matters specifically is that a naive === string comparison short-circuits on the first differing byte, leaking through response timing how much of a guessed signature was correct; a constant-time compare closes that side channel. Do the verification before any side effect — no logging of token data, no database writes, and certainly no swap — so that an unverified request costs an attacker nothing and reveals nothing.
When Webhooks Are Not Enough
Webhooks require a publicly reachable HTTP endpoint. If you are running a local script without a server, use MadeOnSol's WebSocket price alert channel instead — it delivers the same events over a persistent WS connection with no public endpoint required.
Common Pitfalls
Skipping signature verification "just for testing." Test deployments leak. A receiver that ever ran without verification, even briefly, is a receiver someone can drive. Build the verification in from the first commit.
Doing heavy work inside the request handler. The webhook sender expects a fast 200. If you run the full quote-sign-send Jupiter flow inline, a slow RPC can stall the response and risk a delivery being considered failed. Acknowledge with 200 first, then process the buy asynchronously.
Setting drop_pct too tight. On volatile memecoins a small threshold fires constantly. Match the threshold to the token's normal volatility, not a habit of using round numbers.
Tight slippage during dips. As the code notes, liquidity thins during sharp drops. A normal-conditions slippage setting will fail transactions exactly when you want them to fill.
Assuming exactly-once delivery. Network retries can deliver the same event more than once. Make your buy logic idempotent — key it on alert_id plus event type so a duplicate dip event does not buy twice.
How to Extend This
The single-token, single-action receiver here is a foundation. Natural next steps:
Watch many tokens through one endpoint. Create one alert per token, all pointing at the same webhook_url, and branch on token_mint inside the handler. The receiver code does not change; only the alert creation loop does.
Layer in other signals. A price dip is more actionable when smart money agrees. Feeding KOL tracker and signals data alongside the price webhook turns a blind dip-buyer into a confirmation-based one — the full wiring is in the portfolio alert system guide.
Add take-profit on recovery. The recovery event already gives you the trough via dip_low_mc_usd; use it to size and time an exit rather than just logging.
Build it against the broader API. The price alert surface is one of several data feeds — see what else is available on the Solana API and the developer overview at /pricing.
FAQ
What happens if my server is down when a dip fires? That delivery can be missed — webhooks are push, not a queue you poll. Keep the receiver highly available, and lean on the recovery event and your own position monitoring as a backstop rather than assuming every dip event arrives.
Can I change the threshold without recreating the alert? The baseline is captured when the alert is created, so the cleanest way to change behavior is to delete and recreate. Treat alerts as cheap, disposable objects.
Do I have to use Jupiter? No. The webhook only delivers the dip event. What you do after verification — swap, notify, log — is entirely your code. Jupiter is shown because it is the common case for execution, not a requirement.
Webhook or WebSocket? Use a webhook when you have a public HTTPS endpoint and want the server idle between events. Use the WebSocket channel when you are running a local script or otherwise cannot expose an endpoint. The events are the same.
This article is for educational and informational purposes only. Nothing in this article constitutes financial, investment, or trading advice. Automated trading carries extreme risk — bots can lose money faster than manual trading. Always test with small amounts and never risk more than you can afford to lose.