Claim SOL API: Reclaim Rent from Empty Solana Token Accounts
Claim your SOL rent now
Connect a wallet, see the amount, claim in one click. Rent, creator fees and cashback come together.
Free check — nothing happens until you press Claim
Every token you buy on Solana opens a token account, and every token account locks about 0.002 SOL as a deposit ("rent"). When you sell, the tokens leave but the account and its deposit stay. Trade a few hundred pump.fun coins and you have real SOL sitting in empty accounts.
The Claim SOL API finds those accounts, closes them, and sends the SOL back to your wallet. You keep 98%; we take 2%.
- No API key. Just send the request.
- Your keys stay with you. The API builds the transactions, and you sign them on your side.
- Works with SPL Token and Token-2022, including every pump.fun token.
How It Works
Three calls, in this order:
- Scan:
GET /api/reclaim/scanlists the accounts you can close. - Build:
POST /api/reclaimturns those accounts into unsigned transactions. - Sign and send: sign the transactions with your wallet, then
POST /api/reclaim/send.
That's the whole flow. Everything else on this page is optional.
| Endpoint | What it does |
|---|---|
GET https://pumpdev.io/api/reclaim/scan | Find empty and dust accounts in a wallet |
GET https://pumpdev.io/api/reclaim/balance | Check the wallet has enough SOL for the network fee |
POST https://pumpdev.io/api/reclaim | Build the close transactions |
POST https://pumpdev.io/api/reclaim/claims | Build creator-fee and cashback claims (also 2%) |
POST https://pumpdev.io/api/reclaim/send | Send your signed transactions |
POST https://pumpdev.io/api/reclaim/confirm | Record transactions your wallet sent itself |
GET https://pumpdev.io/api/reclaim/stats | Public totals: SOL reclaimed, accounts closed |
GET https://pumpdev.io/api/reclaim/activity | Latest reclaims across all users |
Quick Start
A complete Node.js script that reclaims one wallet. Loop it over as many wallets as you like.
import { VersionedTransaction, Keypair } from '@solana/web3.js';
import bs58 from 'bs58';
const API_URL = 'https://pumpdev.io';
async function reclaimWallet(secretKeyBase58) {
const keypair = Keypair.fromSecretKey(bs58.decode(secretKeyBase58));
const publicKey = keypair.publicKey.toBase58();
// 1. Scan: what can be closed?
const scan = await fetch(`${API_URL}/api/reclaim/scan?publicKey=${publicKey}`).then((r) => r.json());
if (scan.empty.length === 0) return console.log(`${publicKey}: nothing to reclaim`);
console.log(`${publicKey}: ${scan.empty.length} empty accounts, ~${scan.totals.sol} SOL`);
// 2. Build: one unsigned transaction per batch of accounts
const built = await fetch(`${API_URL}/api/reclaim`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ publicKey, accounts: scan.empty.map((a) => a.account) }),
}).then((r) => r.json());
if (built.transactions.length === 0) return console.log('nothing built', built.skipped, built.failed);
// 3. Sign locally
const signed = built.transactions.map((base64) => {
const tx = VersionedTransaction.deserialize(Buffer.from(base64, 'base64'));
tx.sign([keypair]);
return Buffer.from(tx.serialize()).toString('base64');
});
// 4. Send right away (built transactions expire after ~3 minutes), 4 per call
for (let i = 0; i < signed.length; i += 4) {
const results = await fetch(`${API_URL}/api/reclaim/send`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ transactions: signed.slice(i, i + 4) }),
}).then((r) => r.json());
for (const r of results) {
if (r.signature && !r.error) console.log(` landed: ${r.signature}`);
else if (r.error === 'unconfirmed') console.log(` may still land: ${r.signature}`);
else console.log(` ${r.error}: ${r.detail ?? ''}`);
}
}
}
Good to Know
You need a little SOL to start. Solana charges the network fee before a transaction runs, so the SOL you're reclaiming can't pay for it. Keep about 0.000015 SOL per transaction in the wallet. A completely empty wallet can't reclaim anything.
The 2% comes out of the reclaimed SOL, not your balance. It's a transfer placed at the end of the same transaction, after the accounts are closed. No invoice, no separate charge.
Empty accounts are safe. Dust accounts are not free. An empty account holds nothing, so closing it loses nothing. A dust account still holds tokens, and closing it burns them. Check each one's usdValue before you include it.
Send quickly. A built transaction is accepted by /send for about 3 minutes. If you miss that, call /api/reclaim again; resending the old one won't work.
Stale data is fine. The server re-checks every account against the chain before building. A wrong or already-closed address is simply skipped, not an error.
1. Scan a Wallet
GET https://pumpdev.io/api/reclaim/scan?publicKey=<wallet>
Read-only. Sorts every token account in the wallet into three groups: close for free (empty), close after burning the leftover tokens (dust), and leave alone (skipped). Results are cached for 60 seconds.
{
"publicKey": "YourWalletPublicKey",
"feeBps": 200,
"empty": [
{ "account": "Acc1...", "mint": "Mint1...", "program": "token", "lamports": 2039280 }
],
"dust": [
{
"account": "Acc2...", "mint": "Mint2...", "program": "token-2022", "lamports": 2039280,
"amount": "17", "decimals": 6, "uiAmount": "0.000017",
"symbol": "PEPE", "name": "Pepe", "logo": "https://...", "usdPrice": 0.0004, "usdValue": 0.0000068
}
],
"skipped": [
{ "account": "Acc3...", "reason": "frozen" },
{ "account": "Acc4...", "reason": "wsol" }
],
"totals": {
"emptyCount": 1,
"dustCount": 1,
"lamports": 2039280,
"feeLamports": 40785,
"netLamports": 1998495,
"sol": 0.00203928
}
}
| Field | Meaning |
|---|---|
empty | Accounts with zero balance. Close them freely |
dust | Accounts that still hold tokens. Closing burns them, and "dust" can still be worth real money, so check usdValue |
skipped | Accounts we won't touch: frozen (locked by the token's issuer) or wsol (wrapped SOL with a real balance) |
totals | Rent from empty accounts only: gross lamports, the 2% feeLamports, and netLamports you receive |
feeBps | The commission in basis points (200 = 2%) |
Each dust entry also includes symbol, name, logo, uiAmount (the balance in normal units), usdPrice and usdValue (prices from Jupiter, refreshed every ~5 minutes). A null price means unknown, not worthless. The Claim SOL app asks for confirmation before burning anything worth $1 or more.
Very large wallets
A wallet with hundreds of thousands of token accounts is too big for one response. Its scan comes back in pages: the answer lists empty accounts only (dust stays empty) and adds two fields:
| Field | Meaning |
|---|---|
nextCursor | Pass it as &cursor= to get the next page. null on the last page |
progress | { "scanned": 37, "of": 256 }, how far the scan has got |
let page = await fetch(`${API_URL}/api/reclaim/scan?publicKey=${publicKey}`).then((r) => r.json());
const empty = [...page.empty];
while (page.nextCursor != null) {
page = await fetch(`${API_URL}/api/reclaim/scan?publicKey=${publicKey}&cursor=${page.nextCursor}`).then((r) => r.json());
empty.push(...page.empty);
}
Normal wallets never see these fields. Each page takes up to ~8 seconds; continuation pages are limited to 20 per minute.
2. Build the Transactions
POST https://pumpdev.io/api/reclaim
{ "publicKey": "YourWalletPublicKey", "accounts": ["Acc1...", "Acc2..."] }
Pass the addresses you want closed, usually scan.empty (and scan.dust if you're happy to burn it), up to 500 per call. Big lists are split into several transactions automatically, sized so wallets like Phantom don't flag them.
{
"transactions": ["base64-tx-1", "base64-tx-2"],
"batches": [
{ "accounts": ["Acc1...", "Acc2..."], "lamports": 4078560, "feeLamports": 81571 }
],
"skipped": [{ "account": "Acc3...", "reason": "unclosable" }],
"failed": [{ "accounts": ["Acc4..."], "error": "..." }]
}
| Field | Meaning |
|---|---|
transactions | Unsigned transactions (base64). Sign each with the wallet, then send |
batches | One per transaction, same order: which accounts it closes, the rent (lamports) and the 2% fee (feeLamports) |
skipped | Accounts left out: not yours (foreign), already closed (missing), frozen, wsol, or one that failed on its own (unclosable) |
failed | Batches that couldn't be built at all. Try those accounts again later |
3. Send the Signed Transactions
POST https://pumpdev.io/api/reclaim/send
{ "transactions": ["signed-base64-tx-1", "signed-base64-tx-2"] }
Up to 4 transactions per call. You get one result per transaction, in the same order:
[
{ "signature": "5abc..." },
{ "error": "unconfirmed", "signature": "5def..." },
{ "error": "expired", "detail": "..." }
]
| Result | What to do |
|---|---|
{ "signature" } | Done. The SOL is back in the wallet |
unconfirmed | Sent, but confirmation was slow. Check the signature on Solscan before rebuilding |
expired | Too late to land. Build again |
unknown_transaction | Not built by /api/reclaim, older than ~3 minutes, or already sent. Build again |
failed | Rejected on-chain; detail says why |
Sending From a Browser Wallet Instead
Browser wallets such as Phantom trust transactions they send themselves (signAndSendTransaction) more than ones a website sends. If your wallet sends them, skip /send and report the signatures instead so they count in the stats:
POST https://pumpdev.io/api/reclaim/confirm with { "publicKey": "<wallet>", "signatures": ["<sig>", ...] } (up to 4). The results look like /send's.
Ask Phantom for one transaction per request. It blocks any request that carries two or more (signAllTransactions, signAndSendAllTransactions) with "Request blocked — This dApp could be malicious", whatever they contain. A transaction's blockhash expires after about a minute, so rebuild any that have waited through earlier prompts.
Optional Endpoints
Check the Balance
GET https://pumpdev.io/api/reclaim/balance?publicKey=<wallet> returns { "publicKey": "...", "lamports": 12345678 }, never cached.
Use it before building: if the wallet has less than ~0.000015 SOL per transaction, ask the user to top up first. Otherwise the transaction fails simulation, and Phantom shows it as "This dApp could be malicious". A 502 means we couldn't read the balance, not that it's zero.
Claim Creator Fees and Cashback Too
POST https://pumpdev.io/api/reclaim/claims with { "publicKey": "<wallet>" } builds pump.fun creator fee and cashback claims for the same 2%, with no minimum. Sign them together with the reclaim transactions, so a wallet shows one approval for everything, and send them through /send the same way.
{
"transactions": ["<base64 transaction>"],
"claims": [{ "kind": "fees", "lamports": 50000000, "feeLamports": 1000000 }],
"failed": []
}
claims[i] describes transactions[i]; kind is "fees" or "cashback". Nothing to claim returns an empty list. Claims too small to cover their own network fees are left out.
Public Stats and Activity
GET https://pumpdev.io/api/reclaim/stats gives running totals for all users:
{ "solReclaimed": 128.44, "accountsClosed": 61207, "wallets": 4310 }
GET https://pumpdev.io/api/reclaim/activity gives the latest reclaims, newest first (the "Recent activity" table on the Claim SOL app):
{
"items": [
{
"type": "rent", "status": "landed", "wallet": "WalletPublicKey", "accounts": 214,
"lamports": 436405920, "feeLamports": 8728118, "netLamports": 427677802,
"signature": "5VERv8NM...", "createdAt": "2026-09-23T14:02:11.000Z"
},
{
"type": "creator-fees", "status": "prepared", "wallet": "WalletPublicKey", "accounts": null,
"estimatedSol": 1.2841, "signature": null, "createdAt": "2026-09-23T14:01:40.000Z"
}
],
"hasMore": true
}
Each response holds up to 20 rows. When hasMore is true, request the next page by passing the last row's createdAt as before. If that row has a signature, pass it as beforeSignature too, so rows from the same millisecond aren't skipped:
GET https://pumpdev.io/api/reclaim/activity?before=2026-09-23T14:01:40.000Z&beforeSignature=5VERv8NM...
type is "rent", "creator-fees" or "cashback" (ignore any new ones you don't know). landed rows confirmed on-chain and carry exact amounts; prepared rows are claims we built for a wallet to send itself, so they carry only an estimatedSol. Both endpoints are cached for 30 seconds (for activity, the first page only).
Errors
Request errors come back with an HTTP error status and an error message:
| HTTP | error | Fix |
|---|---|---|
| 400 | Invalid or missing publicKey | Pass a valid Solana address |
| 400 | accounts must be a non-empty array | Pass at least one account |
| 400 | accounts must hold at most 500 entries | Split the list across calls |
| 400 | accounts contains an invalid address | Remove the bad address |
| 400 | too_many_batches | The list is too big for one call; split it |
| 400 | transactions must hold at most 4 entries | Send in groups of 4 |
| 502 | Failed to build reclaim transactions | Temporary network problem. Retry |
Why Accounts Now Return Less SOL
Solana's SIMD-0437 lowered rent for new token accounts. Accounts opened before the change still return the full ~0.00204 SOL when closed; accounts opened after it return about 0.0002 SOL. So an old wallet with a long trading history is worth the most to clean up, and that backlog shrinks over time.
Frequently Asked Questions
How much SOL can I reclaim per token account?
About 0.00204 SOL for a token account created before SIMD-0437 lowered the rent rate, and roughly 0.0002 SOL for one created after it. You receive that amount minus the 2% commission and the ~0.000015 SOL network fee per transaction.
Do I need to share my private key?
No. The API only needs your public key. POST /api/reclaim returns unsigned transactions; you sign them locally and pass the signed bytes to /api/reclaim/send.
Will closing accounts destroy my tokens?
Closing an empty account destroys nothing, because its balance is already zero. Closing a dust account burns whatever balance it still holds, so check each entry's usdValue before passing it in. Frozen accounts and wSOL accounts that hold a balance are always skipped.
Why do I need SOL in the wallet to reclaim SOL?
Solana charges the network fee before a transaction runs, so the rent a transaction unlocks can't pay for that same transaction. Keep about 0.000015 SOL per batch in the wallet, and check it with /api/reclaim/balance first.
Does it work for pump.fun tokens and Token-2022?
Yes. The scan covers every SPL Token and Token-2022 account the wallet owns, including the one every pump.fun buy opens.
Next Steps
- Claim SOL App: the same flow in your browser, no code
- Claim Creator Fees: collect pump.fun creator royalties
- Claim Cashback: trader cashback rewards
- Trade API: client-side buy and sell
- ⚡ Lightning Trade: one-call buy/sell