Recover ETH stuck in old smart contracts
All endpoints are read-only GET requests. Responses are JSON with snake_case keys. No authentication required. Data refreshes every 6 hours from onchain Multicall3 scans. Rate limits vary per endpoint (see each section). CORS * enabled.
Check if an Ethereum address has claimable ETH in any tracked contract. Returns per-protocol balances and coverage metadata. Rate limit: 30 req/min per IP.
| Parameter | Type | Description |
|---|---|---|
| address | string | Ethereum address (0x + 40 hex chars) |
curl "https://forgotteneth.com/api/check?address=0xab5801a7d398351b8be11c439e05c5b3259aec9b"
const res = await fetch('https://forgotteneth.com/api/check?address=0xab58...'); const data = await res.json(); console.log(`${data.total_claimable_eth} ETH claimable`);
import requests r = requests.get('https://forgotteneth.com/api/check', params={'address': '0xab58...'}) data = r.json() print(f"{data['total_claimable_eth']} ETH claimable")
{
"address": "0xab5801a7d398351b8be11c439e05c5b3259aec9b",
"checked_at": "2026-04-01T12:00:00.000Z",
"contracts_checked": 117,
"contracts_with_balance": 1,
"total_claimable_eth": "0.035096",
"balances": {
"ens_old": {
"contract": "0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef",
"balance_wei": "35095985789402980",
"balance_eth": 0.03509598578940298,
"deeds": [{ "hash": "0x4271...", "eth": 0.01 }, ...]
}
},
"coverage": {
"etherdelta": { "coverage_pct": 99.8, "scan_date": "2026-03-30 UTC" },
...
}
}
| Field | Type | Description |
|---|---|---|
| address | string | The queried address (echoed back) |
| checked_at | string | ISO 8601 timestamp of the check |
| contracts_checked | number | Number of contracts scanned |
| contracts_with_balance | number | How many contracts have claimable ETH for this address |
| total_claimable_eth | string | Sum of all claimable ETH across contracts |
| balances | object | Per-protocol balance details, keyed by protocol key |
| balances.*.contract | string | Contract address for this protocol |
| balances.*.balance_wei | string | Balance in wei (raw integer as string) |
| balances.*.balance_eth | number | Balance in ETH |
| balances.*.deeds | array? | ENS only. List of deed hashes and their ETH values |
| balances.*.bounty_details | array? | Bounties Network only. Per-bounty IDs and ETH amounts |
| balances.*.epoch_details | array? | Kyber FeeHandler only. Per-epoch reward amounts |
| coverage | object | Coverage metadata for every tracked protocol. coverage_pct = fraction of known depositors indexed. scan_date = last refresh date (UTC) |
Check up to 200 addresses in a single request. Returns only addresses with claimable ETH. Ideal for scanning wallets in bulk. Rate limit: 10 req/min per IP.
| Body Field | Type | Description |
|---|---|---|
| addresses | string[] | Array of Ethereum addresses (max 200) |
curl -X POST "https://forgotteneth.com/api/check-batch" \
-H "Content-Type: application/json" \
-d '{"addresses":["0xab5801a7d398351b8be11c439e05c5b3259aec9b","0xd8da6bf26964af9d7eed9e03e53415d37aa96045"]}'
const res = await fetch('https://forgotteneth.com/api/check-batch', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ addresses: ['0xab58...', '0xd8da...'] }) }); const data = await res.json(); console.log(`Found ${data.found} addresses with ETH`);
import requests r = requests.post('https://forgotteneth.com/api/check-batch', json={'addresses': ['0xab58...', '0xd8da...']}) data = r.json() for addr, info in data['results'].items(): print(f"{addr}: {info['total_claimable_eth']} ETH")
{
"checked": 2,
"found": 1,
"contracts_checked": 120,
"results": {
"0xab5801a7d398351b8be11c439e05c5b3259aec9b": {
"contracts_with_balance": 1,
"total_claimable_eth": "0.035096",
"balances": {
"ens_old": { "contract": "0x6090...", "balance_eth": 0.035 }
}
}
}
}
10 requests per minute. Each request can check up to 200 addresses (2,000 addresses/min). Only addresses with claimable ETH are included in the response.
Overview of all tracked contracts with ETH balances, address counts, and coverage percentages. Rate limit: 30 req/min per IP.
{
"total_eth": 157825.97,
"contract_count": 117,
"contracts": {
"etherdelta": {
"contract": "0x8d12A197cB00D4747a1fe03395095ce2A5CC6819",
"total_eth": 1234.56,
"contract_eth_balance": 1500.00,
"addresses_with_balance": 245119,
"coverage_pct": 99.8,
"scan_date": "2026-03-30 UTC"
},
...
}
}
| Field | Type | Description |
|---|---|---|
| total_eth | number | Sum of all mapped depositor balances across all protocols |
| contract_count | number | Number of tracked contracts |
| contracts.*.total_eth | number | Total ETH mapped to known depositors in this contract |
| contracts.*.contract_eth_balance | number | Actual ETH balance of the contract onchain |
| contracts.*.addresses_with_balance | number | Number of depositors with non-zero balances |
| contracts.*.coverage_pct | number | Percentage of contract ETH mapped to known depositors (total_eth / contract_eth_balance * 100) |
| contracts.*.scan_date | string | When this contract was last scanned (UTC date) |
Detailed metadata for a single protocol: balances, coverage, balance distribution, and monthly TVL history. Rate limit: 60 req/min per IP.
| Parameter | Type | Description |
|---|---|---|
| exchange | string | Protocol key (e.g. etherdelta, ens_old, thedao). See full key list. |
{
"exchange": "etherdelta",
"meta": {
"contract": "0x8d12A197cB00D4747a1fe03395095ce2A5CC6819",
"total_eth": 1234.56,
"contract_eth_balance": 1500.00,
"addresses_with_balance": 245119,
"coverage_pct": 99.8,
"scan_date": "2026-03-30 UTC",
"distribution": {
">=100 ETH": { "count": 10, "total_eth": 2460.18 },
"10-100 ETH": { "count": 150, "total_eth": 3560.60 },
"1-10 ETH": { "count": 1882, "total_eth": 4567.89 },
"0.1-1 ETH": { "count": 8500, "total_eth": 3200.00 },
"0.01-0.1 ETH": { "count": 45000, "total_eth": 1200.00 },
"<0.01 ETH": { "count": 189577, "total_eth": 257.89 }
},
"tvl": [
{ "date": "2018-01", "eth": 150000 },
{ "date": "2026-03", "eth": 1500 }
]
}
}
| Field | Type | Description |
|---|---|---|
| meta.distribution | object | Balance distribution across 6 tiers. Each tier has count (addresses) and total_eth |
| meta.tvl | array | Monthly historical ETH balance from deployment to present. Each entry has date (YYYY-MM) and eth |
| meta.activity | object? | Transaction activity metadata (when available): total transactions, last activity date |
Lightweight endpoint returning total tracked ETH and counts. Ideal for widgets and bots. Rate limit: 60 req/min per IP.
{
"total_eth": 157825.97,
"total_contract_eth": 158786.81,
"contract_count": 117,
"address_count": 521145
}
| Field | Type | Description |
|---|---|---|
| total_eth | number | Total ETH mapped to known depositors |
| total_contract_eth | number | Total ETH actually held in contracts onchain (may differ from total_eth due to unmapped depositors) |
| contract_count | number | Number of tracked contracts |
| address_count | number | Total unique addresses with claimable balances across all contracts |
Static JSON listing all tracked protocols with keys, names, and categories. No rate limit.
[
{ "key": "etherdelta", "name": "EtherDelta", "contract": "0x8d12...", "category": "dex" },
{ "key": "ens_old", "name": "ENS Old Registrar", "contract": "0x6090...", "category": "other" },
{ "key": "thedao", "name": "The DAO", "contract": "0xbb9b...", "category": "ico" },
...
]
Descriptions, categories, deploy dates, theme colors, and slugs for all tracked protocols. Static file, no rate limit.
{
"etherdelta": {
"name": "EtherDelta",
"desc": "The first popular decentralized exchange on Ethereum...",
"category": "dex",
"color": "#6441a5",
"contract": "0x8d12A197cB00D4747a1fe03395095ce2A5CC6819",
"deployed": "February 2016",
"slug": "etherdelta"
},
"ens_old": {
"name": "ENS Old Registrar",
"desc": "The original ENS name registration system...",
"category": "other",
"color": "#5284ff",
"contract": "0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef",
"deployed": "May 2017",
"slug": "ens"
},
...
}
All verified ETH claims made through the site. Includes per-claim tx hashes, ENS deed names, and per-protocol aggregates. Rate limit: 30 req/min per IP.
{
"total_claims": 251,
"unique_addresses": 43,
"total_eth": 1042.66,
"by_protocol": {
"ens_old": { "claims": 208, "eth": 763.45 },
"idex": { "claims": 14, "eth": 273.88 },
...
},
"claims": [
{
"timestamp": "2026-04-01T22:09:17.553Z",
"address": "0x5807a8b404c71cf22eb0bac2e5f2a6c202ebe0a1",
"protocol": "ens_old",
"eth": 118.811,
"tx_hash": "0xc70e253ef2445e...",
"deed_name": "wellsfargo"
},
...
]
}
| Field | Type | Description |
|---|---|---|
| total_claims | number | Total number of claim transactions |
| unique_addresses | number | Unique wallets that have claimed |
| total_eth | number | Total ETH claimed across all transactions |
| by_protocol | object | Aggregate claims and ETH per protocol |
| claims[].timestamp | string | ISO 8601 timestamp of the claim |
| claims[].address | string | Wallet address that claimed |
| claims[].protocol | string | Protocol key |
| claims[].eth | number | ETH amount claimed |
| claims[].tx_hash | string | Ethereum transaction hash (verifiable on Etherscan) |
| claims[].deed_name | string? | ENS only. The domain name of the released deed |
All error responses follow a consistent JSON format with an error field.
| Status | Meaning | Response |
|---|---|---|
| 400 | Invalid or missing parameters | {"error": "Invalid address format"} |
| 404 | Protocol not found | {"error": "Unknown exchange"} |
| 405 | Method not allowed | {"error": "Method not allowed"} |
| 429 | Rate limit exceeded (see per-endpoint limits) | {"error": "Rate limit exceeded. Try again in 1 minute."} |
| 500 | Server error (data unavailable) | {"error": "Summary data not available"} |
All API responses include these headers:
| Header | Value | Description |
|---|---|---|
| Cache-Control | private, max-age=300 | Address checks cached for 5 min. /api/summary and /api/table use s-maxage=3600 (1h CDN cache) |
| X-Content-Type-Options | nosniff | Prevents MIME type sniffing |
| Access-Control-Allow-Origin | * | CORS enabled for all origins — call from any domain |
| Content-Type | application/json | All responses are JSON |
ETH values are in ether (not wei) unless the field name ends in _wei.coverage_pct shows what fraction of depositors we've mapped. 100% means all known depositors are indexed.6 hours. The scan_date field shows when each contract was last scanned./api/check returns per-address balances. All other endpoints return aggregate data only./data/protocols.json or the /api/summary response./data/ are not rate-limited and can be cached freely.