{"record":{"id":"cb86351ef4ce73d6","repo":"jamiepine/voicebox","slug":"pump-fun-swap-api-http-res-status","errorCode":null,"errorMessage":"pump.fun swap-api HTTP ${res.status}","messagePattern":"pump\\.fun swap-api HTTP (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"landing/src/lib/token-stats.ts","lineNumber":409,"sourceCode":"  const json = (await res.json()) as Record<string, { usdPrice?: number } | undefined>;\n  const price = json[mint]?.usdPrice;\n  return typeof price === 'number' ? price : null;\n}\n\n// ── Creator rewards (pump.fun swap-api) ──────────────────────────────────────\n// Lifetime creator fees earned by the creator wallet, in SOL. The swap-api\n// returns a daily series with a running `cumulativeCreatorFeeSOL`; the latest\n// (max) bucket is the lifetime total. The per-coin endpoint is unreliable, so\n// we use the per-creator one.\ninterface CreatorFeeBucket {\n  cumulativeCreatorFeeSOL: string;\n}\nasync function getCreatorRewardsSol(): Promise<number | null> {\n  const res = await fetch(\n    `https://swap-api.pump.fun/v1/creators/${TOKEN_CREATOR_ADDRESS}/fees?interval=1d`,\n    { next: { revalidate: REVALIDATE_S }, headers: { 'User-Agent': 'voicebox.sh' } },\n  );\n  if (!res.ok) throw new Error(`pump.fun swap-api HTTP ${res.status}`);\n  const buckets = (await res.json()) as CreatorFeeBucket[];\n  if (!Array.isArray(buckets) || buckets.length === 0) return null;\n  // Cumulative is monotonic, but take the max defensively.\n  const max = buckets.reduce((m, b) => {\n    const v = Number.parseFloat(b.cumulativeCreatorFeeSOL);\n    return Number.isFinite(v) && v > m ? v : m;\n  }, 0);\n  return max;\n}\n","sourceCodeStart":391,"sourceCodeEnd":419,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/landing/src/lib/token-stats.ts#L391-L419","documentation":"Thrown by getCreatorRewardsSol() when pump.fun's swap-api (swap-api.pump.fun/v1/creators/<TOKEN_CREATOR_ADDRESS>/fees) returns non-2xx while fetching lifetime creator fees. The endpoint returns a daily series with a running cumulativeCreatorFeeSOL; the function takes the max bucket. It is a server-side ISR fetch reusing REVALIDATE_S and sends a custom User-Agent header. Like the Jupiter fetch, the module contract says failures must degrade to null rather than propagate.","triggerScenarios":"GET swap-api.pump.fun/v1/creators/<creator>/fees?interval=1d responds 429, 404 (creator not found / wrong TOKEN_CREATOR_ADDRESS), 401/403, or 5xx. pump.fun also blocks requests lacking an acceptable User-Agent.","commonSituations":"pump.fun swap-api is unofficial and intermittently rate-limited or taken offline for maintenance. A typo or stale TOKEN_CREATOR_ADDRESS yields 404. Removing or changing the 'voicebox.sh' User-Agent can trigger 403s.","solutions":["Wrap getCreatorRewardsSol() in try/catch and degrade creator rewards to null on failure.","Verify TOKEN_CREATOR_ADDRESS in constants matches the pump.fun creator wallet.","Keep the custom User-Agent header ('voicebox.sh'); do not send a bare default UA.","If 429s recur, increase TOKEN_STATS_CACHE_MS to lower hit frequency."],"exampleFix":"// before\nconst rewards = await getCreatorRewardsSol();\n// after\nlet rewardsSol: number | null = null;\ntry {\n  rewardsSol = await getCreatorRewardsSol();\n} catch (e) {\n  warnings.push(`creatorRewards: ${(e as Error).message}`);\n}","handlingStrategy":"fallback","validationCode":"const CREATOR_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\nfunction isValidCreator(addr: string): boolean {\n  return CREATOR_RE.test(addr);\n}\n// Skip the fetch when TOKEN_CREATOR_ADDRESS fails validation.","typeGuard":"function isCreatorFeeBucketArray(v: unknown): v is CreatorFeeBucket[] {\n  return Array.isArray(v) && v.every(\n    (b) => b && typeof (b as CreatorFeeBucket).cumulativeCreatorFeeSOL === 'string',\n  );\n}","tryCatchPattern":"let rewards: number | null = null;\ntry {\n  rewards = await getCreatorRewardsSol();\n} catch (e) {\n  warnings.push(`creatorRewards: ${(e as Error).message}`);\n}","preventionTips":["Keep the custom User-Agent header on the pump.fun request.","Validate TOKEN_CREATOR_ADDRESS as a Solana base58 address before fetching.","Reuse the same REVALIDATE_S cache as other token-stats fetches to bound request volume."],"tags":["network","external-api","pump-fun","solana","typescript","nextjs","isr"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}