Enterprise API
Soundverse Enterprise API
Generate licensed music, vocals, stems, and audio insights from your own product. This page covers auth, the request/response contract, and the two ways to call the API — start here before jumping to a capability page.
- What changed
- Authentication
- Two ways to call this API
- Endpoints
- License tiers
- Idempotency-Key
- Errors
- Polling vs. streaming
- Results and playback
- Rate limits
- Providing audio/file input
- Account balance
What changed
The Enterprise API moved off the old per-capability, per-version REST surface (POST /v6/generate/music, GET /v5/recognize, etc.) onto a single generic pipeline: every generation — songs, music, vocals, stems, copyright checks — goes through one endpoint, POST /v1/generations, with a tool_id that identifies which capability you want.
If you integrated against the old API, you don’t need to rewrite anything yet: most of the old URLs and field names still work, unchanged, via a compatibility layer that resolves the right tool for you server-side. See Compat Routes for the full list, or jump straight to your capability’s page in the sidebar — each one shows the compat route first, if it has one.
Authentication
Every request (except GET /health) requires a bearer API key in the Authorization header:
Authorization: Bearer sksoundverse_<your_api_key>
Content-Type: application/jsonA missing or malformed header returns 401 {"error": "UNAUTHENTICATED"}; an invalid or revoked key returns 401 {"error": "INVALID_API_KEY"}.
Two ways to call this API
There are two ways to create a generation, and you can mix both across your integration:
- Compat routes — old-style URLs and field names (e.g.
POST /v7/generate/song). The gateway resolves the right tool for you; you never need atool_id. Covers most of the commonly-used capabilities. See Compat Routes. - Native pipeline —
POST /v1/generationswith an explicittool_id. Always available, and the only option for capabilities the compat layer doesn’t cover yet (e.g. audio transcription, sound effects, audio effects, similar-music, MIDI-to-song). Look up the righttool_idon the Tool Catalog page.
Endpoints
POST/v1/generationscreate a generation
GET/v1/generations/{id}fetch one task
GET/v1/generationslist your tasks, cursor-paginated
GET/v1/generations/{id}/streamlive SSE progress
GET/v1/files/{file_id}/downloadshort-lived signed download URL
GET/v1/toolslist the tools this account can bill against
GET/v1/account/balanceyour remaining token balance
POST /v1/generations body: tool_id (string, required), license (integer, optional — see below), payload_json (string, a JSON-encoded object of the tool’s own input fields — see each capability page).
It always returns immediately — 201 {"task_id": "...", "status": "queued"} — it never blocks until the generation finishes. From there, poll GET /v1/generations/{id} or open the SSE stream; see Polling vs. streaming below.
License tiers
license is an integer on the request body. Omit it (or send 0) to default to Royalty-Free.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| 0 | LICENSE_UNSPECIFIED | No | — | Not a valid choice — treated as unset. |
| 1 | LICENSE_ROYALTY_FREE | No | — | Default if omitted. |
| 2 | LICENSE_STANDARD | No | — | |
| 3 | LICENSE_DISTRIBUTION | No | — | |
| 4 | LICENSE_SYNC | No | — | |
| 5 | LICENSE_MASTER | No | — |
Pricing is per license tier and varies by capability and version — see the pricing table on each capability’s page, or the consolidated Tool Catalog.
Idempotency-Key
Set an Idempotency-Key header on any create call (native or compat) to make retries safe:
Idempotency-Key: my-client-generated-key-123Up to 200 characters, [A-Za-z0-9_.:-] only. A repeat call with the same key (scoped to your account) returns the original task instead of creating a new one and billing you again — the right thing to set on every create call your client might retry. A missing or malformed key is not an error; the request just proceeds without dedup.
Errors
Two response shapes exist, depending on where the request fails:
Pipeline errors (creating a generation)
Raised anywhere in the enforcement pipeline — tool resolution, rate limiting, billing, input validation. The error field is the exact class name below (use it for programmatic branching, not the HTTP status alone — two of these share a status code):
{"error": "RateLimited", "message": "...", "retryable": true}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| 400 | UnknownTool | No | — | Unknown or inactive tool_id, or (model, operation) pair. Not retryable — fix the request. |
| 402 | InsufficientFunds | No | — | Token reservation failed. message names the shortfall reason; top up your balance and retry. |
| 422 | ToolNotPriced | No | — | The tool has no platform pricing configured for the given license tier — a config gap on our side, not your request. |
| 422 | InvalidGenerationInput | No | — | The payload failed capability-specific validation (e.g. a file field isn't a resolvable upload, an inpaint time range is invalid, a consent id is malformed). message names the offending field. |
| 429 | RateLimited | No | — | Per-tool/per-model rate limit exceeded for your account. retryable: true. |
| 503 | DependencyUnavailable | No | — | A required internal dependency (uploaded-file service, voice-clone consent service, etc.) is unavailable or not yet compatible. retryable: true. |
Other errors
Raised outside the pipeline — auth and resource-ownership checks. These do not carry a retryable field, and FORBIDDEN/NOT_FOUND carry no message either; treat them as non-retryable regardless.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| 401 | UNAUTHENTICATED | No | — | Missing or non-Bearer Authorization header. |
| 401 | INVALID_API_KEY | No | — | Bearer token present but invalid or revoked. |
| 403 | FORBIDDEN | No | — | The task exists but belongs to a different account. Body is just {"error": "FORBIDDEN"} — no message. |
| 404 | NOT_FOUND | No | — | No task with that id. Body is just {"error": "NOT_FOUND"} — no message. |
There are no rate-limit response headers (no X-RateLimit-*, no Retry-After) — the 429 body above is the only signal. Back off and retry with the same Idempotency-Key. Only errors marked retryable: true above (RateLimited, DependencyUnavailable) are safe to retry as-is; retrying any other error without changing the request will fail the same way again.
Polling vs. streaming
Every generation is created async. Once you have a task id, choose either:
- Poll —
GET /v1/generations/{id}for a point-in-time snapshot (status:queued/processing/completed/failed). - Stream —
GET /v1/generations/{id}/stream, an SSE stream ofprogress/streaming_url/partial_outputevents, ending in aterminalevent. Resume a dropped connection with?after=<seq>from the last event you saw; atimeoutorerrorevent also carries a resume cursor.
Both are backstopped server-side — billing settles even if you never poll or stream to completion.
Results, playback, and downloads
A completed audio generation returns one or more output.assets. Each asset includes a durable file_id and blob_hash, and is saved to the authenticated account’s Soundverse Library. Enterprise API outputs are hidden from public/profile surfaces by default. Keep the file_id when you want to download the result or use it as an input to a later Soundverse generation.
To download from your own backend, call GET /v1/files/{file_id}/download. It returns a short-lived signed URL scoped to the API-key owner.
Play completed audio from Library
Open the Soundverse Library while signed in to the same account as the API key. The Library mints an authorized, short-lived playback or download link for the generated file.
Do not treat output.assets[].url as a public browser URL. It is a private storage locator and can return ResourceNotFound when opened directly.
Rate limits
Limits are enforced per tool and per model, per hour and per day, scoped to your account. There are no response headers exposing remaining quota — a 429 on create is the only signal (see Errors above).
Providing audio/file input
Capabilities that take an audio or MIDI input (extend, remix, singing with a reference, stem separation, copyright check, transcription, audio effects) accept the field in any of three shapes:
{"song": {"url": "https://example.com/track.mp3"}}
// or, as shorthand, a bare string is coerced the same way:
{"song": "https://example.com/track.mp3"}A direct URL or inline base64 is usually the right choice for a server-to-server integration — you don’t need to upload anything to a Soundverse-hosted library first. Each capability page documents the exact field name (song, audio, vocal_reference, etc.) and any size/format limits for that field.
Account balance
GET/v1/account/balance
{
"total_effective": 12500,
"base_effective": 10000,
"extra_tokens": 2500,
"base_expires_at": "2026-08-01T00:00:00Z"
}