
Introducing the Parsed Events Scan API
Table of Contents
- Scan by Solana Program Instructions
- What if a Solana program doesn’t have an IDL with named instructions?
- Scan Multiple Solana Programs at Once
- Scan by Token Mint
- Combining Programs and Mints
- Choose a Match Scope
- Track Native SOL
- Get Parsed Transactions, Signatures, or a Count
- Control How Much History Each Request Scans
- Scan Summaries
- How Scan Pagination Works
- Parsed Results Without the Client-Side Pipeline
- Use the Latest Helius SDKs
- Parsed Events Scan API Pricing
- Controlling Usage
- Replacing the Enhanced Transactions API with the Parsed Events API
- What’s the difference?
- Get Started
The new Helius Parsed Events Scan endpoint finds the transactions you need in any Solana address’s history and returns only those, already parsed. Filter by program, instruction, native SOL, token mint, or any combination without needing to build your own historical pipeline.
Scanning is quite cheap. Each request costs 10 credits, plus 1 credit per 1,000 transactions searched. In one test, shared below, the scan endpoint searched 3,402 Pump.fun transactions for the 10 most recent creator fee claims in 182 ms, for 14 credits. Fetching the same transactions with getTransactionsForAddress, for example, would cost 350 credits (i.e., 25x more), before any of them are parsed.
Here's a quick overview:
Before the Scan endpoint, finding one kind of activity in an address’s history meant building the pipeline yourself:
- Fetch a page of signatures
- Request each transaction
- Decode it with your own parsers
- Apply your filters
- Repeat until you have enough matches
On a busy address, you’re stuck processing thousands of transactions before finding a match.
The new Helius Parsed Events Scan API endpoint moves that workflow to the server:
- Send the address and event criteria you care about
- The API scans the address and parses matching transactions
- You receive only what matches: parsed transactions, their signatures, or a count
You can match transactions by:
- Program (any instruction)
- Program and instruction name
- Program and raw instruction discriminator
- Multiple programs in one request (up to 20)
- Token mint address
- Program and token mints
The Scan API also takes slot, time, and signature bounds, as well as status, commitment, sort-order, and token-account filters.
This makes it useful for focused history queries such as:
- Finding every buy or sell instruction for a program
- Finding a wallet’s full trading history across multiple onchain trading venues like Jupiter, DFlow, and Pump.fun
- Finding how many times a wallet interacted with a given program within a specific date range
- Searching programs without an IDL by instruction discriminator
- Watching failed calls to your program with decoded program errors
- Watching administrative or config instructions on a program for fee or parameter changes
The Parsed Events API is the successor to the Enhanced Transactions API (now in maintenance mode). Read our Parsed Events API migration guide to migrate.
Scan by Solana Program Instructions
The following request scans the Pump.fun Program history and returns parsed transactions containing a buy or sell instruction:
curl --request POST \
--url "https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=$HELIUS_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"match": {
"programs": [
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"instructions": ["buy", "sell"]
}
]
},
"limit": 100
}'
Using this request, the Parsed Events Scan demo tool scanned 261 records and found 100 matches. It returned the most recent 100 events in 182 ms, costing only 11 credits in total:
Instruction names can use the spelling from any known version of the program’s IDL or the snake_case form. The Parsed Events Scan API checks both top-level instructions and inner instructions invoked through Cross-program Invocations (CPI).
Programs often have several versions of a given action. For example, Pump.fun’s IDL has buy, buy_exact_sol_in, buy_v2, buy_exact_quote_in_v2, sell, and sell_v2 instructions. The Scan API allows you to list every instruction name you want to match against.
Buys and sells make up much of Pump.fun’s activity, so matching happens rather quickly. Scan saves more when the activity you need is rare. Creator fees, for example, are a small fraction of the program’s transactions:
curl --request POST \
--url "https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=$HELIUS_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"address": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"match": {
"programs": [
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"instructions": ["collect_creator_fee"]
}
]
},
"limit": 10
}'Using the Parsed Events Scan demo tool to find the ten most recent claims, we can see the tool scanned 3,402 transactions in 182 ms and cost 14 credits for this request:
The comparable getTransactionsForAddress call would cost 350 credits, a 25x multiplier compared to the scan endpoint.
What if a Solana program doesn’t have an IDL with named instructions?
To use the Parsed Events Scan API with Solana programs that are missing an IDL, you can match using instruction data prefixes instead.
Each discriminator can contain one to eight hex-encoded bytes. You can combine names and discriminators for a single program; an instruction matches either. For example:
{
"match": {
"programs": [
{
"programId": "<PROGRAM_ADDRESS>",
"discriminators": ["0x66063d1201daebea"]
}
]
}
}Scan Multiple Solana Programs at Once
You can list up to 20 programs in a single Parsed Events Scan API request, and a transaction matches when it calls any one of them.
For example, this request is scanning a wallet’s trades for matches across Jupiter, DFlow, and Pump.fun in a single scan:
{
"address": "<WALLET_ADDRESS>",
"match": {
"programs": [
{
"programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
"instructions": ["route", "shared_accounts_route", "route_v2", "shared_accounts_route_v2"]
},
{ "programId": "DF1ow4tspfHX9JwWJsAb9epbkA8hmpSEAtxXy1V27QBH" },
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"instructions": ["buy", "buy_exact_sol_in", "buy_v2", "sell", "sell_v2"]
}
]
}
}A program listed without any instructions or discriminators matches any of its instructions.
Scan by Token Mint
The Scan API can also find transactions that touched a given token mint by checking each transaction’s pre- and post-transaction token balances for the mint address and, by default, counts only balances that belong to the scanned address.
When you scan a wallet for a token, set tokenAccounts to balanceChanged. There are a variety of cases where an incoming token transfer touches the wallet’s token account only, and not the wallet itself; so the wallet’s history leaves those transactions out by default.
For example, this request finds Ansem’s wSOL activity during September 2026:
curl --request POST \
--url "https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=$HELIUS_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"address": "<ANSEM_WALLET_ADDRESS>",
"match": {
"mints": [{ "mint": "So11111111111111111111111111111111111111112" }]
},
"tokenAccounts": "balanceChanged",
"time": {
"gte": 1788220800,
"lte": 1790812800
}
}'The Scan API found 53 matching transactions after scanning a total of 7,555 transactions:
Combining Programs and Mints
Developers can set both programs and mints to narrow results. When combined, a transaction must satisfy both criteria to match. To narrow a program's activity to a single token, though, the scanned address matters more than the filters.
For example, scan a token’s mint address instead of the Pump.fun program to find every Pump.fun trade of a given token. Each buy or sell lists the mint as an account, so it matches by default:
{
"address": "<MINT_ADDRESS>",
"match": {
"programs": [
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"instructions": ["buy", "buy_exact_sol_in", "buy_v2", "sell", "sell_v2"]
}
]
}
}The mint's history holds only that token's activity, while the program's history holds trades for every token, so scanning it would waste budget on unrelated transactions.
Choose a Match Scope
By default, a program's instructions and a mint's token balances count only when they involve the scanned address. A token balance involves the address when the address owns the token account, or when the address is the balance's mint. An instruction involves the address when:
- One of its accounts is the address
- One of its accounts is a token account that the address owns
- The address is a mint, and one of the instruction’s accounts is a token account for that mint
- The address is the program being called
Set "scope": "transaction" on a program or mint to count it anywhere in the transaction. Use it when the address only pays the fee, executes a multisig tx, or isn't an account of the instruction you match.
For example, this request finds a token's transactions that also moved USDC. Under the default scope, the USDC balances would have to belong to the mint address, and nothing would match:
{
"address": "<MINT_ADDRESS>",
"match": {
"mints": [
{ "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "scope": "transaction" }
]
},
"returnShape": "signatures"
}Programs also take the same match scope. This request finds the Jupiter swaps a relayer paid fees for.
The relayer only signs the transactions as the fee payer, so it isn’t one of the route instruction’s accounts, and none of these transactions would match under the default scope:
{
"address": "<RELAYER_ADDRESS>",
"match": {
"programs": [
{
"programId": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
"instructions": ["route", "shared_accounts_route", "route_v2", "shared_accounts_route_v2"],
"scope": "transaction"
}
]
},
"returnShape": "signatures"
}The same logic applies to a multisig member who executes a proposal. The instruction the multisig runs acts on the vault’s accounts, and not on the member’s, so scanning the member’s history for them needs the transaction scope.
Track Native SOL
Native SOL has no token balances, so the scan matches it on lamports.
Pass the native SOL mint (So11111111111111111111111111111111111111111), which is different from wrapped SOL. A transaction matches when the scanned address’s SOL balance changed, not counting the fee it paid:
{
"address": "<WALLET_ADDRESS>",
"match": {
"mints": [{ "mint": "So11111111111111111111111111111111111111111" }]
},
"time": { "gte": 1788220800, "lt": 1790812800 }
}This catches SOL a program pays out without a transfer instruction, such as a Pump.fun sell. It also catches incidental movements, such as Jito tips and rent paid for or refunded from accounts.
Get Parsed Transactions, Signatures, or a Count
returnShape sets what the response carries for the matches:
returnShape | Response | Use It For |
transactions (default) | Up to limit parsed matches in data | Reading decoded instructions, transfers, and summaries |
signatures | signature, slot, transactionIndex, and blockTime for every match | Backfills and indexers that need the list first |
count | No data; scan.matchedTransactions is the count | Activity checks, eligibility, analytics, etc. |
For example, this request counts a trader's Pump.fun buys in Sep, 2026 without returning transactions:
{
"address": "<WALLET_ADDRESS>",
"match": {
"programs": [
{
"programId": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"instructions": ["buy", "buy_exact_sol_in", "buy_v2"]
}
]
},
"returnShape": "count",
"time": { "gte": 1788220800, "lt": 1790812800 }
}To count, signatures and count ignore limit and cover every match in the range a request scans. To count a long history, keep paging and sum scan.matchedTransactions.
All three shapes cost the same.
Control How Much History Each Request Scans
A scan can inspect up to 10,000 transactions per request, and returns up to 100 matches.
The budget.maxScannedTransactions field controls that limit and defaults to 10,000. The limit field controls how many matches the endpoint returns; it accepts values from 1 to 100 and defaults to 100.
The two controls are separate because matches can be sparse. That is, a request can scan thousands of txs and return only a few matches.
By default, scan requests include only successful transactions.
Set status to failed or any to include failed transactions. Failed transactions come with decoded program errors when the program’s IDL defines them.
Scan Summaries
Every response includes a scan summary:
{
"data": [],
"paginationToken": "460903064:422",
"scan": {
"stoppedOn": "budget",
"scannedTransactions": 2000,
"matchedTransactions": 0,
"scannedThrough": {
"slot": 460903064,
"blockTime": 1792856105
},
"creditsCharged": 12
}
}The summary tells you:
- Why the scan stopped
- How many transactions it scanned
- How many transactions it matched
- The last slot and block time it scanned
- How many credits the request used
How Scan Pagination Works
When a scan stops, the scan.stoppedOn field provides the reason:
windowEnd: scan reached the end of the history or windowlimit: response contains the requested number of matchesbudget: request reached its transaction scan budgetdeadline: request reached its time limit
When the response includes a paginationToken, send that token in the next request, and continue even when the current data array is empty. An empty result can mean the request used its budget before it found a match, not that no later match exists.
For example, this loop collects the last hour of Pump.fun trades.
Note the time bound and the request cap keep it from walking the entire history:
const PUMP_PROGRAM = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
const ONE_HOUR_AGO = Math.floor(Date.now() / 1000) - 3600;
const MAX_REQUESTS = 50;
let paginationToken;
let requests = 0;
async function scanHistory() {
const response = await fetch(
`https://mainnet.helius-rpc.com/v1/parsed-events/scan?api-key=${process.env.HELIUS_API_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
address: PUMP_PROGRAM,
match: {
programs: [{ programId: PUMP_PROGRAM, instructions: ["buy", "sell"] }],
},
time: { gte: ONE_HOUR_AGO },
limit: 100,
...(paginationToken && { paginationToken }),
}),
}
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
return response.json();
}
do {
const page = await scanHistory();
requests++;
for (const transaction of page.data) {
console.log(transaction.signature);
}
paginationToken = page.paginationToken;
} while (paginationToken && requests < MAX_REQUESTS);Parsed Results Without the Client-Side Pipeline
Each item in data uses the same TransactionResult format as the Parsed Events Parse Transactions endpoint. Results can include decoded instructions, transfers, account changes, events, transaction summaries, and protocol-specific parsed data when available. If your application also needs the original Solana transaction payload, set rawTransaction to "json", "jsonParsed", or "base64".
The main difference is where the history workflow runs.
Your application defines the search once while the Parsed Events Scan API handles history pagination, matching, and parsing before returning the relevant transactions.
Use the Latest Helius SDKs
Both our TypeScript and Rust SDKs support our Parsed Events API and the new scan endpoint.
The TypeScript SDK exposes scans as helius.parsedEvents.scan(). The response type follows the returnShape passed in:
const { scan } = await helius.parsedEvents.scan({
address: "<WALLET_ADDRESS>",
match: {
programs: [{ programId: "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P", instructions: ["buy", "sell"] }],
},
returnShape: "count",
});
console.log(scan.matchedTransactions, scan.stoppedOn);The Rust SDK also has scan, scan_signatures, and scan_count available on helius.parsed_events(), all taking the same ScanRequest.
The Scan endpoint is also supported in the Helius CLI and MCP.
Parsed Events Scan API Pricing
Each Parsed Events Scan API request costs 10 credits plus 1 credit for each history page scanned. A history page contains up to 1,000 transactions.
For example, a request using the default 10,000-transaction budget costs at most 20 credits. The response reports the exact charge in scan.creditsCharged.
To compare, scanning costs one-tenth of paging the same history with getTransactionsForAddress, which costs 100 credits per page (up to 1,000 transactions).
Controlling Usage
To control usage, use the narrowest practical address and add slot or time bounds when possible. Fewer unrelated transactions means more useful matches within each request.
Replacing the Enhanced Transactions API with the Parsed Events API
The Enhanced Transactions API remains available in maintenance mode, but it is not receiving new parser types or feature work. Parsed Events is its successor and uses Helius’s IDL catalog to decode instructions across thousands of Solana programs. If you haven’t yet, migrate to the Parsed Events API.
The Parsed Events API uses a different response schema, so existing integrations should follow the migration guide before switching endpoints.
What’s the difference?
The Enhanced Transactions API organizes activity into a fixed set of transaction types, such as swaps, transfers, and NFT sales, while the Parsed Events Scan API supports more precise searches by program instruction, raw discriminator, token mint, or a combination of these criteria. Helius applies those filters while scanning the address history and parses only the matching transactions.
The Parsed Events API gives developers broader program coverage and more control over historical queries without maintaining a client-side scanner.
Get Started
Use the Parsed Events Scan API when you know the onchain activity you need but do not want to build and maintain a client-side history scanner. Read the Scan Transaction History API reference for the complete request schema, response fields, limits, errors, and more examples.
To continue exploring what the Scan API is capable of doing, check out the new Scan tool in your Helius dashboard. Try scanning addresses by program, mints, and with filters.
Related Articles
Subscribe to Helius
Stay up-to-date with the latest in Solana development and receive updates when we post


