Concepts
Errors & limits
Errors are predictable JSON. Every job also reports how much it cost in credits_charged.
Error shape
Every failure comes with success: false and an error object with a stable code (for your code to branch on) and a human-readable message:
{
"success": false,
"error": {
"code": "insufficient_credits",
"message": "Not enough credits."
}
}
Common codes
| HTTP | code | What happened |
|---|---|---|
| 401 | invalid_api_key | Key missing, malformed, invalid, or revoked. |
| 403 | api_disabled | API disabled globally, or your account isn't in the beta / has no active plan. |
| 400 | invalid_request | Invalid parameters (missing field, value outside the enum/range). |
| 400 | insufficient_credits | Not enough balance for the job. Check GET /balance and top up. |
| 404 | not_found | Model slug or generation id doesn't exist. |
| 429 | rate_limit | Rate limit exceeded. Wait and retry (backoff). |
Job failures (async)
The codes above are request errors (returned on the POST /generations HTTP call). An accepted job can still fail during processing — it then comes back with status: "failed" and a stable error.code, one of:
| code | What happened |
|---|---|
insufficient_credits | Account balance can't cover the job cost. |
content_policy_violation | Prompt or media rejected by content policy. |
generation_timeout | The job exceeded the maximum processing time. |
rate_limited | Too many requests per minute during processing. |
invalid_input | A required parameter is missing or outside the model's schema. |
generation_failed | Generic processing failure. |
copyright_conflict | Audio rejected for copyright or a source conflict. Do not automatically retry the same file; use your own or authorized recording. |
These are the same codes listed on every model page. Branch on code, never on message.
Rate limits
Generations are capped at roughly 20 per minute per account (uploads share the same cap). The rest of the /dev surface has a higher global limit. On a 429, apply exponential backoff before retrying.
Credits
credits_charged and credits_net report the net cost after refunds. credits_debited preserves the initial debit and credits_refunded reports the actual ledger refund. A refunded failure returns credits_debited: 29, credits_refunded: 29, credits_charged: 0, credits_net: 0. REST, MCP and webhooks share these fields.
Audio cover
Use suno-upload-and-cover with a public, authorized audio_url. Simple mode uses a transformation prompt (up to 500 characters). Custom mode requires custom_mode: true, style, title, and lyrics in lyrics or prompt for vocal output. Both instrumental and the legacy make_instrumental alias are accepted. Versions: V4, V4_5, V4_5ALL, V4_5PLUS, V5 and V5_5. Source audio must not exceed 8 minutes (1 minute for V4_5ALL). Personas require custom mode and V5/V5_5; output duration of 10–360 seconds requires custom mode and V5_5. A technically valid request can still be rejected by content checks.
Each generation debits credits from the account balance. The cost is model/tool-specific and comes back in credits_charged on the completed job. Check your balance at any time:
curl https://caranguejo.art/api/v1/dev/balance \
-H "Authorization: Bearer $CK"
{ "data": { "credits": 4820 } }