Skip to main content

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

Open the Claim SOL app →Prefer code? Claim through the API ↓

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:

  1. Scan: GET /api/reclaim/scan lists the accounts you can close.
  2. Build: POST /api/reclaim turns those accounts into unsigned transactions.
  3. 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.

EndpointWhat it does
GET https://pumpdev.io/api/reclaim/scanFind empty and dust accounts in a wallet
GET https://pumpdev.io/api/reclaim/balanceCheck the wallet has enough SOL for the network fee
POST https://pumpdev.io/api/reclaimBuild the close transactions
POST https://pumpdev.io/api/reclaim/claimsBuild creator-fee and cashback claims (also 2%)
POST https://pumpdev.io/api/reclaim/sendSend your signed transactions
POST https://pumpdev.io/api/reclaim/confirmRecord transactions your wallet sent itself
GET https://pumpdev.io/api/reclaim/statsPublic totals: SOL reclaimed, accounts closed
GET https://pumpdev.io/api/reclaim/activityLatest 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
}
}
FieldMeaning
emptyAccounts with zero balance. Close them freely
dustAccounts that still hold tokens. Closing burns them, and "dust" can still be worth real money, so check usdValue
skippedAccounts we won't touch: frozen (locked by the token's issuer) or wsol (wrapped SOL with a real balance)
totalsRent from empty accounts only: gross lamports, the 2% feeLamports, and netLamports you receive
feeBpsThe 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:

FieldMeaning
nextCursorPass 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": "..." }]
}
FieldMeaning
transactionsUnsigned transactions (base64). Sign each with the wallet, then send
batchesOne per transaction, same order: which accounts it closes, the rent (lamports) and the 2% fee (feeLamports)
skippedAccounts left out: not yours (foreign), already closed (missing), frozen, wsol, or one that failed on its own (unclosable)
failedBatches 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": "..." }
]
ResultWhat to do
{ "signature" }Done. The SOL is back in the wallet
unconfirmedSent, but confirmation was slow. Check the signature on Solscan before rebuilding
expiredToo late to land. Build again
unknown_transactionNot built by /api/reclaim, older than ~3 minutes, or already sent. Build again
failedRejected 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:

HTTPerrorFix
400Invalid or missing publicKeyPass a valid Solana address
400accounts must be a non-empty arrayPass at least one account
400accounts must hold at most 500 entriesSplit the list across calls
400accounts contains an invalid addressRemove the bad address
400too_many_batchesThe list is too big for one call; split it
400transactions must hold at most 4 entriesSend in groups of 4
502Failed to build reclaim transactionsTemporary 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​