Introduction
SongAPI is a REST API for generating full AI songs — vocals, instruments, and all — from text prompts. All endpoints live under a single base URL:
https://api.songapi.devGeneration is asynchronous. Submission endpoints (/v1/generate, /v1/extend, /v1/cover, /v1/add-vocals, /v1/lyrics) return 202 Accepted immediately with a generation object in status queued. Poll GET /v1/generations/:id until status is "complete", or set a webhook_url and get a webhook when the track is ready. Statuses move queued → processing → complete | failed.
A first request, end to end:
# 1. submit curl https://api.songapi.dev/v1/generate \ -H "Authorization: Bearer $SONGAPI_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "upbeat indie pop song about summer road trips"}' # → 202 { "id": "gen_…", "status": "queued", … } # 2. poll until status is "complete" curl https://api.songapi.dev/v1/generations/gen_… \ -H "Authorization: Bearer $SONGAPI_KEY" # → 200 { "status": "complete", "audio_url": "…", "clips": [ … ] }
## Authentication
Every /v1 request needs an API key passed as a bearer token. Keys are created on the dashboard and shown in full only once, at creation.
Authorization: Bearer sk_live_… # live — bills credits Authorization: Bearer sk_test_… # sandbox — free
Keep keys out of client-side code — call SongAPI from your backend. A missing, malformed, or revoked key returns 401 unauthorized.
## Sandbox
Every account includes a sandbox key (sk_test_…). Sandbox requests are free, use the exact same endpoints and schemas as live, and complete a few seconds after submission with silent placeholder audio — so you can build and test your whole integration (including webhooks) before spending a credit. Sandbox and live generations are separate: a live key never sees sandbox jobs, and vice versa.
## Errors
Errors return a JSON body with a stable error code and, usually, a human-readable message:
{ "error": "invalid_input", "message": "prompt: String must contain at most 3000 character(s)", "details": ["prompt: String must contain at most 3000 character(s)"] }
details is only present on validation failures — one entry per invalid field.
| STATUS | CODE | WHEN |
|---|---|---|
| 400 | invalid_input | Body isn't JSON, or a field failed validation (see details). |
| 401 | unauthorized | Missing, malformed, unknown, or revoked API key. |
| 402 | insufficient_credits | Live key with a balance below the request's cost — top up to continue. |
| 404 | not_found | Unknown generation id or route. |
| 429 | rate_limited | Over 300 requests per minute on one key. |
| 500 | internal_error | Something failed on our side — safe to retry. |
Failed live generations are refunded automatically: credits are debited when a job is accepted and returned in full if it ends in status failed.
## Rate limits
Each API key can make 300 requests per minute; beyond that, requests return 429 rate_limited until the window resets.
Generation throughput is governed separately by per-account concurrency — how many music jobs can render at once (lyrics jobs don't count against it). Submissions above the cap are never rejected: they queue and dispatch as slots free up.
| TIER | CONCURRENT GENERATIONS |
|---|---|
| Default | 2 |
| After a single $500 purchase | 30 |
| After a single $1,250 purchase | 60 |