How to Monitor Solana Wallet Activity via API (2026 Tutorial)
Step-by-step tutorial: monitor Solana wallet activity through an API. Add wallets to a watchlist, poll their swaps with pagination, read per-wallet stats and build a live dashboard in TypeScript.
MadeOnSol··Updated · 9 min read
Building a product on Solana or Robinhood Chain 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.
Building a product on Solana or Robinhood Chain data?
MadeOnSol isn't an RPC or another generic token API — it's Solana & Robinhood Chain memecoin intelligence that's painful to build in-house, pulled from dual-region gRPC shred streams and our own Robinhood Chain node, pushed to your app as events land.
Signals you'd otherwise build
KOL & smart-money flow from 2,000+ labeled wallets, deployer reputation, coordination clusters, linked-wallet entity resolution, and an all-DEX firehose.
The Business tier (€400/mo, self-serve) licenses you to display MadeOnSol data inside your own product — 500k calls/day, 15 WS + 6 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.
Building anything on top of Solana on-chain data — a trading dashboard, a copy-trading bot, a portfolio tracker — means you need reliable wallet monitoring at the foundation. Polling an RPC node for every wallet in your watchlist is slow, expensive, and fragile. A dedicated wallet tracking API handles the indexing for you and gives you clean, filterable data over a simple HTTP or WebSocket interface.
This guide walks through setting up wallet monitoring from scratch using the Solana API from MadeOnSol. By the end you will have a working TypeScript implementation that adds wallets to a watchlist, polls swap history with pagination, and surfaces per-wallet statistics — everything you need to build a bot or dashboard on top.
Before writing any code it helps to understand what the API actually indexes. When you add a wallet to your watchlist, the service starts tracking every swap and SPL token transfer that wallet makes. Events are retained for 120 days and are queryable immediately after they are ingested. If you need to follow a program rather than a wallet, our companion guide on how to track Solana program activity — instructions, events, and CPI chains covers that lower-level approach.
The core endpoints you will use:
GET /api/v1/wallet-tracker/watchlist — list all wallets in your watchlist (up to 50 on Pro, 100 on Ultra, 500 on Business)
POST /api/v1/wallet-tracker/watchlist — add a wallet with an optional label
DELETE /api/v1/wallet-tracker/watchlist/{address} — remove a wallet
PATCH /api/v1/wallet-tracker/watchlist/{address} — update a wallet's label
GET /api/v1/wallet-tracker/trades — paginated swap and transfer history, filterable by wallet, action type, and event type
GET /api/v1/wallet-tracker/summary — per-wallet aggregates: swap count, buy/sell split, SOL volume, and last event timestamp
The Wallet Tracker needs a Pro plan or higher. A Free key gets 403 tier_required on every /wallet-tracker/* route; there is no delayed free access. Plans are on the pricing page, and the full endpoint reference is in the API docs.
Setting Up the TypeScript SDK
The fastest way to get started is with the official TypeScript SDK (madeonsol). Install it alongside the standard Solana web3 library:
Initialize the client in a shared module you can import across your project:
// src/client.ts
import { MadeOnSol } from 'madeonsol';
export const client = new MadeOnSol({
apiKey: process.env.MADEONSOL_API_KEY!,
});
Step 1: Building Your Watchlist
The first thing your monitoring system needs is a list of wallets to track. Let's write a utility that adds wallets in bulk and handles the case where a wallet is already tracked:
// src/watchlist.ts
import { client } from './client';
export async function addWallets(wallets: { address: string; label: string }[]) {
const results: { address: string; success: boolean; error?: string }[] = [];
for (const wallet of wallets) {
try {
await client.walletTracker.addToWatchlist({
wallet_address: wallet.address,
label: wallet.label,
});
console.log(`Added ${wallet.label} (${wallet.address.slice(0, 8)}...)`);
results.push({ address: wallet.address, success: true });
} catch (err: any) {
// 409 is returned both for "already in watchlist" (fine) and for
// "wallet limit reached" (a real error), so check the message
if (err.status === 409 && /already/i.test(err.message)) {
results.push({ address: wallet.address, success: true });
} else {
console.error(`Failed to add ${wallet.address}: ${err.message}`);
results.push({ address: wallet.address, success: false, error: err.message });
}
}
}
return results;
}
export async function getWatchlist() {
// { wallets: [{ wallet_address, label, added_at }], count, limit, remaining }
return client.walletTracker.watchlist();
}
You can then call addWallets with whatever seed list you have — wallets from an on-site tool like the KOL tracker, whale addresses you have sourced manually, or any other list.
Step 2: Polling Trade History
Once wallets are tracked, the trades endpoint is your primary data source. It returns swap and transfer events sorted by time descending, and supports cursor-based pagination so you can efficiently fetch only new events on each poll cycle.
Single-Page Fetch
Here is the basic fetch, getting the 50 most recent events for a specific wallet:
block_time and ingested_at are when MadeOnSol indexed the event; slot is the on-chain position. The response wraps events as { events, count, ordered_by, next_cursor, next_cursor_slot }.
Incremental Sync
For a production system you do not want to process events you have already seen. The simplest reliable pattern is to fetch the newest page on every poll and skip any tx_signature you have already handled:
// src/sync.ts
import { client } from './client';
// In production you would persist this set to a database or Redis
const seen = new Set<string>();
export async function syncNewTrades(walletAddress: string) {
const { events } = await client.walletTracker.trades({
wallet: walletAddress,
limit: 200,
});
const fresh = events.filter((e) => !seen.has(e.tx_signature));
for (const e of fresh) seen.add(e.tx_signature);
return fresh;
}
To walk further back in history, page with the cursor the response returns: pass next_cursor_slot back as before_slot together with order=slot (see the API docs). Keep one ordering for the whole walk, because next_cursor (the legacy before cursor) orders by indexing time instead of slot.
Filtering by Action Type
If you only care about buy swaps (for a copy-trading signal feed, for example), pass action: 'buy' to avoid processing sells:
Supported event_type values are swap and transfer. Supported action values are buy and sell.
Step 3: Using the Summary Endpoint
Polling individual trade events is useful for real-time monitoring, but for building a dashboard that shows wallet-level health you want the summary endpoint. It gives you aggregated stats per wallet without having to crunch raw events yourself:
// src/summary.ts
import { client } from './client';
export async function getWatchlistSummaries() {
const { wallets } = await client.walletTracker.summary({ period: '7d' });
// Sort by most recently active
return wallets.sort((a, b) =>
new Date(b.last_event_at ?? 0).getTime() - new Date(a.last_event_at ?? 0).getTime()
);
}
export function formatSummary(s: any) {
const winRate = s.swap_count > 0
? ((s.buys / s.swap_count) * 100).toFixed(1)
: '0';
return {
label: s.label ?? s.wallet_address.slice(0, 8) + '...',
swaps: s.swap_count,
buys: s.buys,
sells: s.sells,
solBought: s.sol_bought.toFixed(2),
solSold: s.sol_sold.toFixed(2),
lastSeen: new Date(s.last_event_at).toLocaleString(),
};
}
The sol_bought and sol_sold fields give you net flow — a wallet that consistently buys more SOL-denominated value than it sells is accumulating, which is often a useful signal on its own.
Step 4: Building a Poll Loop
Tie everything together into a poll loop that runs on an interval and processes new events:
// src/monitor.ts
import { getWatchlist } from './watchlist';
import { syncNewTrades } from './sync';
import { getWatchlistSummaries } from './summary';
async function processEvent(event: any) {
// Your logic here: send to Discord, store in DB, trigger a trade, etc.
console.log(
`[${event.action.toUpperCase()}] ${event.label ?? event.wallet_address.slice(0, 8)} | ` +
`${event.token_symbol} | ${event.sol_amount} SOL`
);
}
async function pollCycle() {
const watchlist = await getWatchlist();
for (const entry of watchlist.wallets) {
const newTrades = await syncNewTrades(entry.wallet_address);
for (const event of newTrades) {
await processEvent(event);
}
}
}
// Run every 30 seconds
setInterval(pollCycle, 30_000);
pollCycle(); // run immediately on start
For higher-frequency monitoring, consider using the wallet_tracker:event webhook (Pro plan or higher) instead of polling — it pushes events to your endpoint the moment they are indexed, eliminating the 30-second lag. The API docs have full webhook configuration details.
Common Pitfalls
Do not poll faster than your plan allows. The API rate limits are per-minute per key. If you have 50 wallets on PRO and poll each one every 10 seconds you will hit limits. Batch summary fetches and use cursors to keep per-poll request counts low.
Persist what you have seen. The in-memory Set in the example above resets on restart. In production, store handled tx_signature values in a database or Redis so you do not reprocess events across restarts.
Label your wallets. The label field is optional but you will thank yourself later when you have 50 addresses in your watchlist and need to debug a strange trade. Use labels like "KOL: Arthur Hayes" or "Whale: $50M bag".
Check last_event_at before processing. The summary endpoint is cheap. Poll it first to see which wallets have had recent activity, then fetch full trade history only for those wallets.
What to Build Next
With wallet monitoring in place, the natural next steps are:
Copy-trading signal feed — filter buy events above a SOL threshold and forward them to your execution engine. See our guide on how to build a Solana trading bot for the execution side.
Portfolio dashboard — aggregate summaries across your watchlist and display net flow, win rate, and activity heatmaps. The portfolio trackers solution shows how a watchlist event becomes a user-facing activity row.
The Solana API also exposes a deployer intel feed and KOL-specific endpoints that you can layer on top of wallet monitoring for richer signal. The Wallet Tracker starts on the Pro plan with 50 tracked wallets, which is enough to validate most use cases before you scale up. A free key is still useful for exploring the KOL and deployer endpoints first.