The TopWallets API v1 exposes three features: token scans with their top 300 wallets, individual wallet scans, and cross-token wallet correlation. Responses use one envelope: { data, meta?, request_id } on success, { error: { code, message, details? }, request_id, documentation_url } on failure.
https://www.topwallets.ai/api/v1The machine-readable contract lives at /openapi/v1.json (OpenAPI 3.1). Import it into Postman or Insomnia, or generate a typed client from its operationIds.
Every request needs a Bearer key issued by the TopWallets team (format tw_live_…, tied to an active Pro or Premium profile). Keys are stored hashed and shown once at creation; never ship them to a browser.
Authorization: Bearer tw_live_YOUR_KEYMissing or unknown key → 401. Valid key on a free plan, with a missing profile, or when the subscription cannot be verified → 403 FORBIDDEN_PLAN (the API fails closed).
60 requests per minute per key (fixed window, enforced durably across all server instances; per-key overrides possible). Responses carry X-RateLimit-Limit / -Remaining / -Reset (omitted while the counter store is briefly unreachable, fail-open); a 429 includes Retry-After.
| Plan | Scans / day (token scan trigger + wallet scan) | Reads / day (top-wallets + wallet GET) |
|---|---|---|
| Pro | 10 | 50 |
| Premium | 50 | 500 |
Quotas reset at UTC midnight and share the same pools as web-app usage. Reusing an already-running token scan costs nothing. Correlations are per-minute limited and metered but have no daily cap in v1.
Asynchronous job: trigger, poll, read. A typical scan analyzes ~300 wallets in 2–5 minutes.
| Step | Endpoint | Notes |
|---|---|---|
POST | /tokens/{mint}/scans | 202 + scan_id. Idempotent: a scan active within the last 15 min is reused (reused: true, no quota consumed). |
GET | /scans/{scan_id} | Poll every Retry-After (5 s). stalled: true after 20 min without progress ⇒ safe to re-trigger. A failed scan can also be re-triggered (a fresh trigger consumes quota). |
GET | /tokens/{mint}/top-wallets?limit=300 | Token + up to 300 wallets with full stats and 1d/7d/30d history. Readable mid-scan (partial results). |
BASE="https://www.topwallets.ai/api/v1"
KEY="tw_live_YOUR_KEY"
MINT="DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263"
SCAN_ID=$(curl -s -X POST "$BASE/tokens/$MINT/scans" \
-H "Authorization: Bearer $KEY" | jq -r '.data.scan_id')
while :; do
STATUS=$(curl -s "$BASE/scans/$SCAN_ID" -H "Authorization: Bearer $KEY")
S=$(echo "$STATUS" | jq -r '.data.status')
STALLED=$(echo "$STATUS" | jq -r '.data.stalled')
[ "$S" != "processing" ] && break
[ "$STALLED" = "true" ] && echo "stalled — re-trigger the scan" && break
sleep 5
done
curl -s "$BASE/tokens/$MINT/top-wallets?limit=300" \
-H "Authorization: Bearer $KEY"POST /wallets/{address}/scan is synchronous (< 60 s): fetch, score, store, return. GET /wallets/{address} is the cheap database-only read. data.source tells you what you got: fresh (provider, this request), cache (< 1 h old, bypass with {"force_refresh": true}) or stale-fallback (provider failed, older data served).
Note: the POST consumes a daily scan even when the response comes from cache; use the GET for free-form reads (it only consumes a daily read).
curl -s -X POST "https://www.topwallets.ai/api/v1/wallets/4Nd1mYbJ6PXvDra3DnzgUtQVtUUSDtdQZFLz4WqQbfvF/scan" \
-H "Authorization: Bearer tw_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"force_refresh": false}'GET /correlations?tokens=mint1,mint2&limit=100 returns wallets that traded at least 2 of the given tokens (2–5 mints), ordered by overlap count. Set-overlap counting, not statistical correlation: winners / first_buyers restrict each token's list to its top-100 by realized PnL / earliest buyers. Paginate with limit (max 500) and offset (max 100000); meta.truncated signals more rows. Unscanned mints appear in meta.tokens_missing; trigger a token scan for each, then re-query.
curl -s "https://www.topwallets.ai/api/v1/correlations?tokens=DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263,EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&limit=100" \
-H "Authorization: Bearer tw_live_YOUR_KEY"| Code | Status | Meaning |
|---|---|---|
UNAUTHORIZED | 401 | Missing, unknown or revoked API key |
FORBIDDEN_PLAN | 403 | The key's profile is not on a Pro/Premium plan |
QUOTA_EXCEEDED | 403 | Daily quota exhausted; details carry used, limit and resets_at |
VALIDATION_ERROR | 400 | Invalid parameter; details list each field and the received value |
TOKEN_NOT_SCANNED | 404 | No report for this token yet; details.trigger is the call to make |
SCAN_NOT_FOUND | 404 | Unknown scan id |
WALLET_NOT_FOUND | 404 | Wallet not in the index yet |
RATE_LIMITED | 429 | Per-minute limit hit; honor Retry-After |
UPSTREAM_ERROR | 502 | The upstream data provider failed |
UPSTREAM_TIMEOUT | 504 | The provider or the correlation query timed out |
INTERNAL_ERROR | 500 | Unexpected error; report the request_id |
Every error body carries a documentation_url and the request_id to include in support requests.
The original bot endpoints stay available for existing integrations. New integrations should use the v1 API above.
https://www.topwallets.ai/api/bot/solanaReturns a list of top-performing wallets based on their trading performance over a 7-day period.
| Parameter | Type | Description |
|---|---|---|
| limit | number | Maximum number of wallets to return (default: 100, max: 100) |
curl -X GET \
"https://www.topwallets.ai/api/bot/solana/top-wallets?limit=50" \
-H "Authorization: Bearer YOUR_API_KEY"{
"success": true,
"message": "Successfully fetched top wallets",
"data": [
{
"all": {
"score": number,
"winrateScore": number,
"pnlScore": number,
"roiScore": number,
"consistencyScore": number,
"address": string,
"formattedAddress": string,
"winrate": number,
"tokenTraded": number,
"averageHoldingTime": string,
"realizedPnl": string,
"unrealizedPnl": string,
"realizedRoi": string,
"unrealizedRoi": string,
"combinedRoi": string,
"realizedPnlRaw": number,
"unrealizedPnlRaw": number,
"realizedRoiRaw": number,
"unrealizedRoiRaw": number,
"combinedRoiRaw": number,
"combinedPnlRaw": number,
"totalInvested": number | string | null,
"totalInvestedFormatted": string | null,
"averageBuyAmount": number | string | null,
"averageBuyAmountFormatted": string | null,
"totalWins": number | null,
"totalLosses": number | null,
"lossPercentage": number | null,
"name": string | null,
"twitter_url": string | null,
"picture_url": string | null,
"type": "normal" | "kols",
"isFavorite": boolean,
"updatedAt": string
},
"30d": { /* Same structure as 'all' */ },
"7d": { /* Same structure as 'all' */ },
"1d": { /* Same structure as 'all' */ }
}
// ... more wallet trading data
]
}| Status | Description |
|---|---|
401 | Unauthorized - Invalid API key |
404 | No top wallets found |
500 | Internal server error |