{"record":{"id":"e35f7d2839ecf21a","repo":"jackwener/OpenCLI","slug":"suno-api-insufficient-credits-http-402-detai","errorCode":null,"errorMessage":"Suno API: insufficient credits (HTTP 402). ${detail}","messagePattern":"Suno API: insufficient credits \\(HTTP 402\\)\\. (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":402,"severity":"error","filePath":"clis/suno/utils.js","lineNumber":335,"sourceCode":"        const res = await fetch('${STUDIO_API}/api/generate/v2-web/', {\n            method: 'POST',\n            headers: ${sunoHeadersJs(deviceId, { 'Content-Type': 'application/json' })},\n            body: ${JSON.stringify(bodyJson)},\n        });\n        const text = await res.text();\n        let parsed = null;\n        try { parsed = JSON.parse(text); } catch {}\n        return { status: res.status, ok: res.ok, body: parsed, raw: parsed ? null : text.slice(0, 600) };\n    })()`));\n\n    if (!result || !result.ok) {\n        const status = result?.status || 'unknown';\n        const detail = result?.body?.detail || result?.raw || JSON.stringify(result?.body || {}).slice(0, 500);\n        if (status === 401 || status === 403) {\n            throw new AuthRequiredError(SUNO_DOMAIN, `Suno API rejected request (HTTP ${status}). Re-login on suno.com.`);\n        }\n        if (status === 402) {\n            throw new CommandExecutionError(`Suno API: insufficient credits (HTTP 402). ${detail}`);\n        }\n        throw new CommandExecutionError(`Suno generate failed (HTTP ${status}): ${detail}`);\n    }\n\n    if (!result.body || typeof result.body !== 'object' || Array.isArray(result.body)) {\n        throw new CommandExecutionError('Suno generate returned malformed JSON payload.');\n    }\n    const clips = result.body?.clips || [];\n    if (!clips.length) {\n        throw new EmptyResultError('suno generate', `Submission accepted but Suno returned no clip ids. Raw: ${JSON.stringify(result.body).slice(0, 300)}`);\n    }\n    return result.body;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Poll /api/feed/v3 (cookie auth, no Bearer).\n// ─────────────────────────────────────────────────────────────────────────────\n","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/utils.js#L317-L353","documentation":"When Suno's generate API answers HTTP 402, the account lacks generation credits; submitSunoGeneration converts that into CommandExecutionError('Suno API: insufficient credits (HTTP 402). <detail>'). `detail` comes from the API's body.detail, raw body, or a truncated JSON dump, often naming the credit type needed.","triggerScenarios":"Submitting a generation request when the signed-in Suno account has run out of monthly/c subscription credits (or the required credit tier for the requested model, e.g. V5.5), so the API returns 402 Payment Required.","commonSituations":"Free-tier daily credits exhausted; end of monthly billing cycle; attempting an expensive model generation with only basic credits; shared account where a teammate consumed the credits.","solutions":["Wait for credit refresh (daily/monthly reset) or upgrade your Suno subscription to get more credits.","Switch to a cheaper model version via the model option (e.g. chirp-v4 instead of chirp-fenix) if your credits tier allows it.","Check the detail suffix in the message — it usually names which credit balance is short.","Verify the right account is signed in; you may be hitting an account with no credits."],"exampleFix":"// before\nopencli suno generate --prompt \"song\" --model chirp-fenix   // HTTP 402\n// after (use a model your credits cover, or top up at suno.com)\nopencli suno generate --prompt \"song\" --model chirp-v4","handlingStrategy":"try-catch","validationCode":"// Check credit state via a cheap feed/session call before generating\nconst session = await ensureSunoSession(page, deviceId);\nif (!session.ok || session.credits === 0) throw new Error('No Suno credits — top up at suno.com');","typeGuard":"function isInsufficientCreditsError(err) {\n  return err && /insufficient credits \\(HTTP 402\\)/.test(err.message || '');\n}","tryCatchPattern":"try {\n  await submitSunoGeneration(page, params);\n} catch (err) {\n  if (isInsufficientCreditsError(err)) {\n    console.error('Out of credits: top up at suno.com or wait for reset.');\n  } else throw err;\n}","preventionTips":["Monitor your Suno credit balance and top up before batch generation.","Prefer cheaper model versions when credits are low.","Queue generations and stop on the first 402 instead of hammering the API.","Don't retry on 402 — it is deterministic, not transient."],"tags":["suno","credits","billing","http-402"],"backgroundTag":"quota-exceeded","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}