jamiepine/voicebox · warning · Error

pump.fun swap-api HTTP ${res.status}

Error message

pump.fun swap-api HTTP ${res.status}

What it means

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.

Source

Thrown at landing/src/lib/token-stats.ts:409

  const json = (await res.json()) as Record<string, { usdPrice?: number } | undefined>;
  const price = json[mint]?.usdPrice;
  return typeof price === 'number' ? price : null;
}

// ── Creator rewards (pump.fun swap-api) ──────────────────────────────────────
// Lifetime creator fees earned by the creator wallet, in SOL. The swap-api
// returns a daily series with a running `cumulativeCreatorFeeSOL`; the latest
// (max) bucket is the lifetime total. The per-coin endpoint is unreliable, so
// we use the per-creator one.
interface CreatorFeeBucket {
  cumulativeCreatorFeeSOL: string;
}
async function getCreatorRewardsSol(): Promise<number | null> {
  const res = await fetch(
    `https://swap-api.pump.fun/v1/creators/${TOKEN_CREATOR_ADDRESS}/fees?interval=1d`,
    { next: { revalidate: REVALIDATE_S }, headers: { 'User-Agent': 'voicebox.sh' } },
  );
  if (!res.ok) throw new Error(`pump.fun swap-api HTTP ${res.status}`);
  const buckets = (await res.json()) as CreatorFeeBucket[];
  if (!Array.isArray(buckets) || buckets.length === 0) return null;
  // Cumulative is monotonic, but take the max defensively.
  const max = buckets.reduce((m, b) => {
    const v = Number.parseFloat(b.cumulativeCreatorFeeSOL);
    return Number.isFinite(v) && v > m ? v : m;
  }, 0);
  return max;
}

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Wrap getCreatorRewardsSol() in try/catch and degrade creator rewards to null on failure.
  2. Verify TOKEN_CREATOR_ADDRESS in constants matches the pump.fun creator wallet.
  3. Keep the custom User-Agent header ('voicebox.sh'); do not send a bare default UA.
  4. If 429s recur, increase TOKEN_STATS_CACHE_MS to lower hit frequency.

Example fix

// before
const rewards = await getCreatorRewardsSol();
// after
let rewardsSol: number | null = null;
try {
  rewardsSol = await getCreatorRewardsSol();
} catch (e) {
  warnings.push(`creatorRewards: ${(e as Error).message}`);
}
Defensive patterns

Strategy: fallback

Validate before calling

const CREATOR_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
function isValidCreator(addr: string): boolean {
  return CREATOR_RE.test(addr);
}
// Skip the fetch when TOKEN_CREATOR_ADDRESS fails validation.

Type guard

function isCreatorFeeBucketArray(v: unknown): v is CreatorFeeBucket[] {
  return Array.isArray(v) && v.every(
    (b) => b && typeof (b as CreatorFeeBucket).cumulativeCreatorFeeSOL === 'string',
  );
}

Try / catch

let rewards: number | null = null;
try {
  rewards = await getCreatorRewardsSol();
} catch (e) {
  warnings.push(`creatorRewards: ${(e as Error).message}`);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/cb86351ef4ce73d6. Report an issue: GitHub.