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

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/json

A 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:

  1. 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 a tool_id. Covers most of the commonly-used capabilities. See Compat Routes.
  2. Native pipelinePOST /v1/generations with an explicit tool_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 right tool_id on 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/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.

FieldTypeRequiredDefaultDescription
0LICENSE_UNSPECIFIEDNoNot a valid choice — treated as unset.
1LICENSE_ROYALTY_FREENoDefault if omitted.
2LICENSE_STANDARDNo
3LICENSE_DISTRIBUTIONNo
4LICENSE_SYNCNo
5LICENSE_MASTERNo

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-123

Up 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)

{"error": "RateLimited", "message": "...", "retryable": true}
FieldTypeRequiredDefaultDescription
400UnknownToolNoUnknown or inactive tool_id / (model, operation) pair.
402InsufficientFundsNoToken reservation failed — top up your balance.
422ToolNotPricedNoNo platform pricing configured for this tool + license.
429RateLimitedNoRate limit exceeded. retryable: true.

Other errors

FieldTypeRequiredDefaultDescription
401UNAUTHENTICATED / INVALID_API_KEYNoSee Authentication above.
403FORBIDDENNoThe task belongs to a different account.
404NOT_FOUNDNoNo task with that id.

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.

Polling vs. streaming

Every generation is created async. Once you have a task id, choose either:

  • PollGET /v1/generations/{id} for a point-in-time snapshot (status: queued / processing / completed / failed).
  • StreamGET /v1/generations/{id}/stream, an SSE stream of progress / streaming_url / partial_output events, ending in a terminal event. Resume a dropped connection with ?after=<seq> from the last event you saw; a timeout or error event also carries a resume cursor.

Both are backstopped server-side — billing settles even if you never poll or stream to completion.

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" }