Public API v1
Read-only JSON over HTTPS. No key needed for modest use; sign in to create a key for a higher limit. Everything the pages show, the API returns too.
Basics
- Base URL:
https://sol.wales/api/v1. All responses areapplication/json; charset=utf-8. - CORS is open for
GETandOPTIONS, so browsers can call it directly. - Rate limit: 60 requests per minute per IP without a key, 600 per minute with one. Over the limit you get
429with aRetry-Afterheader. Every response carriesX-RateLimit-LimitandX-RateLimit-Remaining. - Responses carry
Cache-Control: public, max-age=30(or more): the data itself only changes when the sync runs, every few minutes for a batch of wallets. - Amounts are strings in UI units (SOL, or the token's decimals applied).
solLamportsis a string too (it can exceed 2^53). Times are ISO 8601 in UTC. - Errors look like
{ "error": "message" }with a 4xx/5xx status.
API keys (optional)
Sign in and create a key on your account page. It starts with sw_ and is shown once. Send it as Authorization: Bearer sw_… or X-API-Key: sw_…. An invalid or revoked key returns 401; leaving it out just falls back to the anonymous limit.
Endpoints
GET /api/v1/traders?source=
All actively tracked wallets, ordered like the leaderboard (24h moves, 7d moves, SOL balance). source=discovered returns only wallets found by discovery, source=manual only the ones added by an admin; anything else is a 400.
curl https://sol.wales/api/v1/traders?source=discovered
{
"traders": [
{
"address": "…",
"label": null,
"tags": ["auto:balance"], // auto:balance | auto:move says which threshold promoted it
"source": "discovered", // discovered | manual
"active": true,
"addedAt": "2026-09-29T10:00:00.000Z",
"firstSeenAt": "2026-09-29T09:30:00.000Z", // discovered wallets: first sighting
"retiredAt": null,
"retiredReason": null,
"lastSyncedAt": "2026-09-29T12:00:00.000Z",
"lastMoveAt": "2026-09-29T11:58:12.000Z",
"solLamports": "123456789000",
"sol": 123.456789,
"tokenCount": 12,
"moves24h": 8,
"moves7d": 31
}
],
"source": "discovered",
"generatedAt": "…"
}GET /api/v1/traders/:address
One wallet with its last 60 balance snapshots and last 20 moves. 404 when the address is not tracked.
{
"trader": { … as above … },
"snapshots": [{ "at": "…", "solLamports": "…", "sol": 1.5, "tokenCount": 3 }],
"moves": [ … see below … ]
}GET /api/v1/traders/:address/moves?since=&limit=
Moves of one wallet, newest first. since is an ISO date or a unix timestamp (seconds or milliseconds); limit defaults to 50, max 200.
{
"moves": [
{
"signature": "…",
"at": "2026-09-29T11:58:12.000Z",
"kind": "swap", // sol_in | sol_out | token_in | token_out | swap | other
"mint": "…" | null, // primary asset; null means SOL
"amount": "1234.5", // of the primary asset, always >= 0
"counterparty": "…" | null, // best guess for plain transfers
"detail": { // the raw deltas the kind was derived from
"solLamports": "-2500000000",
"fee": "5000",
"tokens": [{ "mint": "…", "delta": "1234500000", "decimals": 6 }]
},
"trader": { "address": "…", "label": "…" }
}
]
}GET /api/v1/moves/recent?limit=
The newest moves across all active wallets (default 50, max 200). Poll this to follow everyone at once.
How the data is produced
- Discovery. Every half hour a job samples the 40 latest signatures of each of jupiter-v6, raydium-amm-v4, orca-whirlpool, pump-fun, fetches a bounded number of those transactions and records their signers as candidates with the size of their SOL move. Candidate balances are read in bulk. A wallet is promoted to the list (source
discovered) once it held at least 1,000 SOL, or moved at least 250 SOL in one transaction while still holding 100 SOL, on 2 separate runs. Known exchange hot wallets, programs and non-wallet accounts are never promoted. Every run is capped at 150 RPC calls. - Sync. Every few minutes the 25 least-recently-synced wallets are re-read: SOL balance, the number of SPL token accounts with a balance, and the 25 most recent signatures. Transactions not seen before are fetched with
jsonParsedencoding and classified from the wallet's pre/post SOL and token balances. A snapshot is stored when the balance changed or an hour passed. - Retirement. A wallet whose balance stays under 100 SOL for 7 days becomes
active: falsewith aretiredReason; its history stays available at/api/v1/traders/:address. - Window: only the latest 25 signatures per sync are inspected. A wallet doing hundreds of transactions in ten minutes will have gaps. Failed transactions are skipped.
- Swap means one asset left and another arrived in the same transaction;
mint/amountdescribe what arrived. SOL changes under 0.005 SOL are treated as fees/rent, not transfers. Only the classic SPL token program is counted fortokenCount. - Wallet labels are written by hand by the site's admins; discovered wallets have none. Nothing is inferred about who owns a wallet, and being on the list only means the thresholds above were met.
- Pages and the API read from the database only; they never query an RPC node on request.
Fair use
Cache what you fetch, honour Retry-After, and identify your client with a User-Agent. Abuse reports and questions: hbouma01@gmail.com.
Disclaimer
Not financial advice. sol.wales shows public on-chain data as read from a Solana RPC node, on a delay and with a limited window per wallet. Wallet labels are curated by hand and can be wrong; transaction classification is heuristic. Nothing here is a recommendation to buy, sell or copy anything. No guarantees of accuracy, completeness or availability. You act on your own responsibility.