Suno Cloud v1 Migration Guide
This guide is the public contract and migration runbook for existing Suno Cloud
clients. OmnAPI exposes nine compatibility endpoints at the original /v1
paths so you can separate the host and credential cutover from the later API
redesign.
Compatibility status
Section titled “Compatibility status”All nine covered routes are implemented. Request names, the main success
shapes, real clip IDs, and the live service’s 200/201 success status rules
are preserved. Differences that protect account isolation, use OmnAPI credits,
or reflect the OmnAPI task model are listed in Deliberate differences.
| Method | Compatibility path | Supported purpose | Modern destination |
|---|---|---|---|
POST | /v1/generate | Custom, extend, upload-extend, cover, or Persona music | Suno songs/derive routes, or a generic upload-extend task |
POST | /v1/generate-gpt | Simple prompt-to-song generation | POST /api/v1/suno/songs with mode: "simple" |
POST | /v1/generate/lyric | Lyrics generation | POST /api/v1/suno/lyrics |
POST | /v1/concatenate | Concatenate an existing extended clip | Generic concat-music task |
GET | /v1/songs | Compatibility resource lookup and recent results | Clip lookup or task history, depending on the query |
GET | /v1/songs/lyric-stamp | Aligned lyrics timeline | GET /api/v1/suno/clips/{clipId}/timeline |
GET | /v1/info | Compatibility credit-account view | Dashboard and usage export |
POST | /v1/stems | Basic two-stem export | POST /api/v1/suno/clips/{clipId}/export |
POST | /v1/generate-wav | WAV export | POST /api/v1/suno/clips/{clipId}/export |
Every other Suno Cloud path is outside this compatibility contract.
Base URL and authentication
Section titled “Base URL and authentication”https://api.omnapi.comThe compatibility paths are mounted directly under /v1; there is no
additional /legacy prefix.
Both header names are accepted:
api-key: YOUR_OMNAPI_KEYx-api-key: YOUR_OMNAPI_KEYThe header name can remain unchanged during phase one, but the credential value cannot. Create a new OmnAPI API key in the dashboard; existing Suno Cloud key values are not portable. Grant these scopes as needed:
| Scope | Used by |
|---|---|
task:create | The six POST endpoints |
task:read | /v1/songs and /v1/songs/lyric-stamp |
usage:read | /v1/info |
All six write routes accept Idempotency-Key, including the zero-credit lyrics
task. Reuse the same key only when retrying the same logical request with an
unchanged body. Deduplication is scoped to the customer and exact compatibility
route; it does not span a different /v1 route, a modern /api/v1 route, or
the old Suno Cloud host.
curl https://api.omnapi.com/v1/info \ -H "api-key: $OMNAPI_KEY"Compatibility responses include:
Deprecation: @1784073600Link: <https://docs.omnapi.com/legacy/suno/>; rel="deprecation"; type="text/html"The Deprecation value is an RFC 9745 Structured Field Date: it marks the
compatibility surface as deprecated from 2026-07-15T00:00:00Z. It is not the
retirement date. If a retirement date is scheduled, the response also carries
a Sunset header; treat that value as authoritative.
ID dictionary
Section titled “ID dictionary”Do not treat every field containing “id” as interchangeable.
| Field | Meaning | Safe use |
|---|---|---|
id | Compatibility resource-row ID in the OmnAPI data store | /v1/songs?ids=... for resources created through OmnAPI |
mid | Real Suno clip ID | Follow-up clip operations and /v1/songs?mids=... |
taskId | Legacy generation-operation identifier when available | Preserve only for old client compatibility; do not use it to poll OmnAPI |
omnapiTaskId | Stable OmnAPI task UUID added to music responses | GET /api/v1/tasks/{omnapiTaskId} |
pollUrl | Ready-to-use canonical task URL | Poll task state and recover after a wait timeout |
Generation endpoints wait for a real music resource. They do not fabricate an
id or mid from a task UUID. When a real clip cannot be acknowledged within
the compatibility wait window, the request returns an error with task recovery
details instead of a placeholder song.
Shared music response
Section titled “Shared music response”/v1/generate, /v1/generate-gpt, and /v1/stems return an array.
/v1/concatenate returns one object.
{ "id": "019c...", "mid": "4fd8...", "taskId": "legacy-generation-id", "omnapiTaskId": "019d...", "pollUrl": "/api/v1/tasks/019d...", "url": "https://example.com/song.mp3", "video": "https://example.com/song.mp4", "cover": "https://example.com/cover.jpeg", "title": "Late Train", "tags": "city pop, warm bass", "prompt": "[Verse] ...", "mv": "chirp-fenix", "duration": 123, "status": "submitted", "type": "generated", "concatBy": null, "syncedAt": "2026-07-15T08:00:01.000Z", "reGenId": null, "createdAt": "2026-07-15T08:00:00.000Z", "updatedAt": "2026-07-15T08:00:01.000Z"}The compatibility shape also contains older fields such as identity, uid,
payload, detail, and notes. Legacy ownership and execution-provider
identifiers are empty or redacted; other compatibility fields may be
reconstructed from OmnAPI records. Do not introduce new dependencies on those
fields.
Request validation
Section titled “Request validation”Legacy JSON DTO failures return HTTP 422. JSON booleans and numbers must use
their real JSON types; strings such as "true" and "42" are not coerced for
the covered generation DTOs. Unknown body properties do not change task
behavior.
The following legacy model values are accepted:
chirp-auk-turbochirp-v4chirp-aukchirp-bluejaychirp-crowchirp-fenixThe live Suno Cloud guard selected chirp-fenix for every supported value
except the exact chirp-auk-turbo value. The compatibility API keeps that
selection rule. Malformed model values return 422 instead of reproducing the
old validation bypass. A fenix/pro request is not automatically downgraded to
turbo when fenix capacity is unavailable; handle the returned availability or
service error instead of assuming a lower model ran.
An optional config extension is accepted on write requests:
{ "config": { "priority": 5, "webhookUrl": "https://example.com/webhooks/omnapi", "tags": ["migration"], "metadata": { "orderId": "ord_123" } }}On the compatibility surface, priority accepts a number or numeric string,
is rounded, and is clamped to 1–10. tags entries are converted to strings;
an empty webhookUrl is ignored; a non-object metadata becomes an empty
object. Prefer the canonical modern limits: priority 1–10, at most 20 tags of
100 characters each, an object for metadata, and a valid URI for webhookUrl.
Feature-specific modern Suno routes keep these values inside config. Generic
/api/v1/tasks and /api/v1/tasks/sync requests instead put priority,
tags, metadata, and webhookUrl at the request top level.
Modern field and response mapping
Section titled “Modern field and response mapping”| Legacy operation or mode | Modern request mapping |
|---|---|
| GPT generation | Suno songs body: mode: "simple"; gpt_description_prompt → prompt; make_instrumental → instrumental; effective legacy model → model |
| Custom generation | Suno songs body: mode: "custom"; legacy prompt → lyrics (or modern prompt); title/tags keep their names; effective legacy model → model |
| Persona generation | Suno songs body: mode: "vox", plus personaId and the Persona root clip as artistClipId; copy prompt, title, and tags |
| Extend | Path clip ID = continue_clip_id; derive body uses action: "extend", continue_at → continueAt, effective legacy model → model, plus prompt/title/tags |
| Cover | Path clip ID = cover_clip_id; derive body uses action: "cover", effective legacy model → model, plus prompt/title/tags |
| Upload-extend | Generic task model suno/chirp-fenix/upload-extend; put clipId, prompt, title, tags, and continueAt inside inputParameters |
| Lyrics | Suno lyrics body uses prompt; omit legacy lyrics_model for equivalent single-candidate behavior |
| Stems / WAV | Path clip ID = mid; export body is { "format": "stems", "stemsMode": "two" } or { "format": "wav" } |
“Effective legacy model” is important: use chirp-auk-turbo only when the
legacy value was exactly chirp-auk-turbo; use chirp-fenix for every other
accepted legacy value or when mv was absent. Copying chirp-v4,
chirp-bluejay, or chirp-crow directly into modern model would change the
behavior that the compatibility guard preserved.
Modern write routes return HTTP 200 with a CreateTaskResponse task receipt;
poll its taskId. The generic sync route returns SyncTaskResponse with HTTP
200 at terminal state or 202 on timeout. Modern clip reads also return the
OmnAPI task/result envelope. They do not return the raw legacy music object.
The compatibility API permits some empty required strings because the live DTO
did; modern simple/custom routes require meaningful generation text. Normalize
empty prompts before phase-two migration.
POST /v1/generate
Section titled “POST /v1/generate”Custom music generation and the four legacy derivative dispatch modes.
| Field | Type | Required | Limit and behavior |
|---|---|---|---|
prompt | string | Yes | Maximum 5,000 characters; an empty string remains valid |
title | string | Yes | Maximum 80 characters; an empty string remains valid |
tags | string | Yes | Maximum 1,000 characters; an empty string remains valid |
mv | string | No | Defaults to the legacy fenix behavior described above |
task | string | No | extend, upload_extend, cover, or vox |
continue_clip_id | string | Conditional | Required by extend and upload_extend |
continue_at | number | No | Non-negative continue point in seconds; string or negative numbers return 422. Absent/null is omitted for extend and becomes 0 for upload-extend |
cover_clip_id | string | Conditional | Required by cover |
persona_id | string | Conditional | Selects Persona music; required when task is vox |
Dispatch order is Persona, extend, upload-extend, cover, then custom. Supplying
continue_clip_id without task selects extend. Cover dispatch requires the
exact task: "cover"; cover_clip_id by itself does not select cover. Turbo
is supported only for custom generation and extend. Extend, upload-extend, and
cover sources must have a current-customer OmnAPI creation record. Persona
generation likewise requires a current-customer Persona creation record.
The old DTO could admit a negative continue_at, but OmnAPI will not schedule
one. Normalize stored values to >= 0 before cutover.
Success
Section titled “Success”HTTP 201 with LegacyMusic[]. The call may wait up to 180 seconds for real
clip rows. Extend and upload-extend return their derivative candidates; the
compatibility route does not concatenate them automatically. Call
POST /v1/concatenate explicitly when the old workflow did so.
curl -X POST https://api.omnapi.com/v1/generate \ -H "api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-123-generate" \ -H "Content-Type: application/json" \ -d '{ "prompt": "[Verse]\nNeon rain on the station floor...", "title": "Late Train", "tags": "city pop, warm bass, female vocal", "mv": "chirp-fenix" }'Modern migration
Section titled “Modern migration”- Custom generation:
POST /api/v1/suno/songswithmode: "custom". - Persona generation:
POST /api/v1/suno/songswithmode: "vox", the owned Persona aspersonaId, and that Persona’s root clip asartistClipId. - Extend and cover:
POST /api/v1/suno/clips/{clipId}/derive, usingaction: "extend"oraction: "cover". - Upload-extend has no one-to-one operation in the modern resource API. Use
generic
POST /api/v1/taskswith modelsuno/chirp-fenix/upload-extendand input fieldsclipId,prompt,title,tags, andcontinueAt. - Store the returned modern
taskId, then pollGET /api/v1/tasks/{taskId}.
POST /v1/generate-gpt
Section titled “POST /v1/generate-gpt”Simple prompt-to-song generation.
| Field | Type | Required | Limit and behavior |
|---|---|---|---|
gpt_description_prompt | string | Yes | Maximum 3,000 characters; an empty string remains valid |
make_instrumental | boolean | Yes | Must be a JSON boolean |
mv | string | No | Uses the legacy model-selection rule |
Success is HTTP 201 with LegacyMusic[]; the real-clip wait budget is 180
seconds.
curl -X POST https://api.omnapi.com/v1/generate-gpt \ -H "api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-124-generate" \ -H "Content-Type: application/json" \ -d '{ "gpt_description_prompt": "uplifting synth pop about a red-eye flight", "make_instrumental": false }'Migrate to POST /api/v1/suno/songs with mode: "simple", map
gpt_description_prompt to prompt, and map make_instrumental to
instrumental.
POST /v1/generate/lyric
Section titled “POST /v1/generate/lyric”| Field | Type | Required | Limit and behavior |
|---|---|---|---|
prompt | string | Yes | Maximum 200 characters; an empty string remains valid |
lyrics_model | string | No | Validated for legacy compatibility but intentionally has no model-selection effect |
Success is HTTP 201 with a legacy lyrics object containing id, status,
text, title, createdAt, and optional tags. The route waits up to 30
seconds. A failed or timed-out task returns a structured error; it is not
converted into a successful object with empty lyrics. Its id and createdAt
come from the customer-owned OmnAPI resource row, not the external lyrics ID.
curl -X POST https://api.omnapi.com/v1/generate/lyric \ -H "api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-125-lyrics" \ -H "Content-Type: application/json" \ -d '{"prompt":"bittersweet indie pop about moving away"}'Migrate to POST /api/v1/suno/lyrics. The compatibility route accepts but
ignores lyrics_model; omit it for the equivalent modern single-candidate
request. The modern lyricsModel option is intended for paired candidates.
The modern API returns a task receipt and supports canonical polling.
POST /v1/concatenate
Section titled “POST /v1/concatenate”| Field | Type | Required | Behavior |
|---|---|---|---|
mid | string | Yes | Source extended clip ID |
The source must have a current-customer OmnAPI creation record. Success is HTTP
201 with one LegacyMusic object. A fresh request waits up to 200 seconds for
the generation acknowledgement and first persisted task-result row; it does
not wait for terminal completion, so the returned status can still be
submitted. A completed, customer-owned concat result may be reused. The cache
is isolated by customer and accepts only completed concat-music results.
As in suno-cloud, the legacy object’s taskId remains an empty string; use
the additive omnapiTaskId and pollUrl fields for canonical task tracking.
curl -X POST https://api.omnapi.com/v1/concatenate \ -H "api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-126-concat" \ -H "Content-Type: application/json" \ -d '{"mid":"clip_123"}'There is no one-to-one dedicated concat operation in the modern Suno resource API. Use the generic task API when exact concat behavior is required:
curl -X POST https://api.omnapi.com/api/v1/tasks \ -H "x-api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-126-concat-modern" \ -H "Content-Type: application/json" \ -d '{ "model": "suno/chirp-fenix/concat-music", "inputParameters": {"clipId":"clip_123"} }'The generic async route immediately returns a task receipt; poll its canonical
task URL. Use /api/v1/tasks/sync only when your new client intentionally wants
to wait for a terminal result. Do not replace concatenate with a new extend
request: extending and concatenating an existing extended clip are different
operations.
GET /v1/songs
Section titled “GET /v1/songs”| Query | Type | Behavior |
|---|---|---|
ids | comma-separated string | Match compatibility resource-row IDs |
mids | comma-separated string | Match clip IDs |
take | integer string | Valid range 1–50; effective maximum 30; default 20 |
skip | non-negative integer string | Validated but intentionally ignored to match the live query behavior |
When both ids and mids are present, they are combined as an intersection.
Results are customer-isolated and sorted newest first. Duplicate clip IDs are
collapsed to the newest resource row. Legacy type is reconstructed from the
creating operation (concatenated, stemed, uploaded, or generated). With
no ID filters, the route returns recent music resources from the OmnAPI data
store; lookup-only rows are not promoted into creation history. While a task is
running, provider feed snapshots refresh the row’s queued/streaming state
and available media URLs; terminal sibling failures retain their own notes
and detail instead of inheriting only a task-level error.
curl "https://api.omnapi.com/v1/songs?mids=clip_123,clip_456&take=20" \ -H "api-key: $OMNAPI_KEY"Success is HTTP 200 with LegacyMusic[].
Modern migration depends on the old query:
mids:GET /api/v1/suno/clips?ids=clip_123,clip_456.ids: there is no equivalent because compatibility row IDs are not clip IDs; migrate your stored references tomidoromnapiTaskIdfirst.- Recent listing: use
GET /api/v1/tasks?providerCode=suno, then read the task resources. The modern clip batch endpoint requires explicit clip IDs.
Long-running status synchronization
Section titled “Long-running status synchronization”Suno can acknowledge a generation quickly and leave its clips non-terminal for much longer. Treat these resource statuses as follows:
| Clip status | Meaning | Client action |
|---|---|---|
submitted | Accepted by Suno; usually changes in about 3–5 seconds | Keep polling; do not resubmit |
queued | Waiting for Suno capacity; usually changes in about 5–10 seconds | Keep polling; do not resubmit |
streaming | Media is being produced; commonly lasts at least 15 seconds | Keep polling; partial URLs are not a terminal guarantee |
complete | Terminal success | Persist the clip and media URLs |
error | Terminal Suno failure | Read notes/detail and the OmnAPI task error |
The compatibility Worker polls near the observed fast path—approximately 3
seconds for submitted, 5 seconds for queued, and 15 seconds for
streaming—then backs off for old tasks through 30-second, 2-minute, 5-minute,
and 15-minute tiers. The hard observation window is 48 hours from the Provider
acknowledgement, not from the start of an API queue delay. Temporary empty feed
responses or temporarily missing sibling clips are not treated as 404 or
terminal failure before that deadline.
A compatibility POST may stop waiting before the Provider reaches a terminal
state. This is only a synchronous HTTP wait timeout; it does not cancel or fail
the durable task. Save omnapiTaskId and pollUrl, poll the canonical task,
and use /v1/songs?mids=... when clip IDs are already known. Do not create a
replacement request with a new idempotency key. For application polling, add
jitter and follow the same increasing cadence instead of querying every second
for hours.
There is one safety-first acknowledgement-loss case. If OmnAPI started the
Suno submission but did not receive a definitive response, the task remains
PROCESSING. An internal
PROVIDER_SUBMISSION_OUTCOME_UNKNOWN diagnostic is retained for support, but
the public Suno and compatibility responses do not present it as a terminal
failure. OmnAPI deliberately does not submit the request again because Suno
may already have created and charged for the clips. Keep polling the original
task and contact support with its omnapiTaskId; support can reconcile a
confirmed Suno clip ID. If no creation can be confirmed, the 48-hour
observation deadline is followed by a 24-hour reconciliation grace before the
final failure/refund safety net (about 72 hours from the submission boundary).
Never switch to a new idempotency key for this task.
GET /v1/songs/lyric-stamp
Section titled “GET /v1/songs/lyric-stamp”Pass either mid (the clip ID) or id (the compatibility resource-row ID).
The resource must belong to the current OmnAPI customer. Requiring one value
and resolving id safely corrects the live service’s ineffective id
handling.
curl "https://api.omnapi.com/v1/songs/lyric-stamp?mid=clip_123" \ -H "api-key: $OMNAPI_KEY"Success is HTTP 200 with the aligned timeline object, including fields such
as aligned_words, waveform_data, hoot_cer, and is_streamed. The wait
budget is 30 seconds. Empty success bodies are not used for failures.
Migrate to GET /api/v1/suno/clips/{clipId}/timeline.
GET /v1/info
Section titled “GET /v1/info”Success is HTTP 200 with an OmnAPI credit-account view plus familiar aliases:
| Field | Meaning |
|---|---|
creditsLeft, leftCredits | Exact available OmnAPI credit balance |
currentUsage | Total used OmnAPI credits |
totalPurchased | Total purchased credits |
totalRefunded | Total refunded credits |
tier | Current account tier |
apiKeyId | Current OmnAPI API-key ID |
apikey | Empty compatibility field; the credential secret is never echoed |
openid | Empty compatibility field; internal customer IDs are not exposed |
packages | Empty compatibility array; package rows are not recreated |
expiredAt | null compatibility field |
usage | 0 compatibility alias |
requestMeta | { "type": "profile" } compatibility alias |
updatedAt | Credit-account update time |
The compatibility API never echoes the API-key secret.
curl https://api.omnapi.com/v1/info \ -H "api-key: $OMNAPI_KEY"There is no exact modern package-object replacement. Use the dashboard for the
current balance, GET /api/v1/usage/export for automated usage reports, and
each task descriptor’s creditsRequired, creditsCharged, and refunded
fields for request-level reconciliation.
POST /v1/stems
Section titled “POST /v1/stems”Body: { "mid": "clip_123" }. The source must have a current-customer OmnAPI
creation record and its resource status must be complete; otherwise the route
returns 404 or 406 before creating a paid task.
Success is HTTP 201 with LegacyMusic[]. The compatibility operation creates
the basic two-stem result and retains the old type: "stemed" spelling. It
waits up to 180 seconds for real music resources. As in suno-cloud, each
legacy object’s taskId remains an empty string; use its additive
omnapiTaskId and pollUrl fields for canonical task tracking.
curl -X POST https://api.omnapi.com/v1/stems \ -H "api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-127-stems" \ -H "Content-Type: application/json" \ -d '{"mid":"clip_123"}'Migrate to POST /api/v1/suno/clips/{clipId}/export with:
{ "format": "stems", "stemsMode": "two"}POST /v1/generate-wav
Section titled “POST /v1/generate-wav”Body: { "mid": "clip_123" }. The source must have a current-customer OmnAPI
creation record and its resource status must be complete; otherwise the route
returns 404 or 406 before creating a paid task.
Success is HTTP 201 with a non-null WAV URL:
{ "url": "https://example.com/song.wav"}The wait budget is 45 seconds. A completed task without a WAV URL is a
structured 502 error; the route no longer returns { "url": null } as a
successful export.
A 504 after this wait does not mean that WAV conversion was rejected. It
means OmnAPI already created and charged the export task, but the URL was not
materialized within 45 seconds. The conversion continues asynchronously. Read
the returned taskId/pollUrl until terminal, or replay the exact legacy route,
body, and Idempotency-Key to recover the original task. Do not submit another
export with a new key, and do not fail over this in-flight write to the modern
route.
curl -X POST https://api.omnapi.com/v1/generate-wav \ -H "api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-128-wav" \ -H "Content-Type: application/json" \ -d '{"mid":"clip_123"}'Migrate to POST /api/v1/suno/clips/{clipId}/export with
{ "format": "wav" }. The modern route returns a Task receipt immediately;
poll links.task instead of waiting for the URL in the create response:
curl -X POST https://api.omnapi.com/api/v1/suno/clips/clip_123/export \ -H "x-api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: order-128-wav-modern" \ -H "Content-Type: application/json" \ -d '{"format":"wav"}'{ "taskId": "019d...", "status": "PENDING", "creditsRequired": 5, "links": { "task": "/api/v1/tasks/019d...", "stream": "/api/v1/tasks/019d.../stream", "resource": null, "final": null }}Credits and settlement
Section titled “Credits and settlement”Suno Cloud package deductions are not reproduced. OmnAPI deducts the quoted
credits atomically when a task is created and records settlement in the task
and credit ledger. Eligible failed tasks and cancellations that were safely
completed before submission or explicitly confirmed by the Provider are
refunded. A post-submit 409 means the task remains active and was not
refunded; keep polling it.
Current standard prices are:
| Operation | Standard OmnAPI credits |
|---|---|
| Song generation and generative derive | 25 |
| Basic two-stem export | 28 |
| Concatenate | 5 |
| WAV export | 5 |
| Lyrics generation and timeline read | 0 |
Customer pricing can change the final quote. Treat creditsRequired on the
task receipt and creditsCharged/refunded on the terminal task as
authoritative. See Credits & Billing.
Error and retry contract
Section titled “Error and retry contract”Compatibility errors use the OmnAPI envelope:
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "title must be a string" }}| HTTP | Typical meaning | Retry guidance |
|---|---|---|
400 | Valid JSON but an unsupported operation combination | Correct the request |
401 | Missing, invalid, disabled, or expired OmnAPI key | Replace or enable the key |
402 | Insufficient OmnAPI credits; no task was created | Add credits, then retry the unchanged request with the same idempotency key |
403 | API-key scope or IP policy rejected the request | Correct the key scope or IP policy |
404 | Referenced target does not exist or lacks current-customer creation provenance | Do not blind-retry or probe other customer resources |
406 | Stems/WAV source exists but is not complete | Wait for the source task to complete, then retry the unchanged request and key |
409 | Key/body mismatch, concurrent request, or a task was already created | Different body: use a new key. No taskId: back off and retry the same key; if it remains unbound for 15 minutes, contact support rather than changing keys. With taskId: poll that task and do not resubmit |
422 | Legacy DTO type, length, enum, or required-field failure | Correct the request |
429 | Request limit reached | Back off using the response headers |
502 | Task completed without the required compatibility resource | Read task details before deciding to retry |
503 | Queue backpressure or no eligible provider capacity before execution | Back off with the same host, route, body, and idempotency key; if the error includes a task ID, poll it instead of resubmitting |
504 | Compatibility wait expired after a task was created | Poll the pollUrl. For a write request, retry only the original host and route with the same key; a same-key replay returns 409 with the original taskId. The timeline GET has no idempotency key and should use its returned task recovery details |
5xx | Service failure | Before task creation, retry with backoff and the same key. If details contain taskId, poll it and never switch keys |
For the six write routes, an idempotency claim is released when validation,
ownership, or credit checks fail before a task exists. Task creation now binds
COMMITTED + taskId in the same PostgreSQL transaction as the charge, Task,
credit ledger, and durable dispatch row; the same binding rule applies to every
created task, paid or zero-credit. A lost database response, or a later
compatibility wait/mapping 500/502/504, therefore cannot leave a newly
created task unbound or make a same-route retry create a second task.
For a composite legacy workflow such as Persona creation, each child-task transaction advances that same claim to the latest committed child. If a later database response is lost, a same-key retry therefore exposes the furthest task already created for the workflow, rather than only its first prerequisite.
An old claim with no visible taskId is still not automatically discarded.
It can be a pre-atomic-binding migration row or a request that stopped before
task creation; support must compare Task, credit ledger, request hash, and logs
before repairing or releasing it. Clients should keep the original key and
contact support after 15 minutes rather than switching keys. This preserves old
customers’ financial history while new writes use the atomic path.
There is no shared idempotency namespace across the compatibility API, the modern API, and the old host. After an uncertain write, poll the returned task details or replay the exact original host, path, key, and body. Never fail over an individual in-flight write between surfaces; move only cohorts whose prior writes are known to be settled or absent.
Deliberate differences
Section titled “Deliberate differences”These differences are part of the public contract and will not be changed to copy unsafe or incompatible legacy behavior.
| Area | Suno Cloud behavior | OmnAPI compatibility behavior |
|---|---|---|
| Credential | Existing Suno Cloud key value | New OmnAPI key value; either header name is accepted |
| Authentication errors | Commonly 403 | 401 for key authentication; 403 only for key scope or IP policy |
| Insufficient balance | Commonly 403 | 402 |
| Billing | Package-based deduction after generation | Atomic create-time deduction with terminal settlement and eligible refund |
| Long-tail status | Frequent legacy feed sync could still leave tasks stale or expire with process-local state | Durable PostgreSQL task state, adaptive polling, 48-hour Provider-acknowledged observation window, and restart/multi-node recovery |
| Submission acknowledgement loss | A process retry could repeat a non-idempotent Suno write | Automatic replay stops at the durable submission boundary; reconcile the original task or wait through the 48-hour observation window plus 24-hour reconciliation grace instead of creating a replacement |
| Source ownership | Some follow-up operations could use another customer’s clip | Follow-up operations and cached results are customer-isolated and require creation provenance |
| History | MySQL song rows and physical IDs | Only OmnAPI task/resource history is queryable |
| Old resources | A known old clip or Persona ID could be routed by legacy runtime state | Extend, upload-extend, cover, Persona generation, concatenate, stems, WAV, and timeline reads require a matching current-customer OmnAPI creation record |
| Query provenance | A clip returned by a lookup could later be reused as a source | Only create/upload and other operations that generate a new owned resource — including generative derive, concatenate, edits/remaster, Persona creation, and stems — establish provenance. Query, timeline, WAV, and other read-only/conversion results do not |
| Model validation | Malformed mv values could be rewritten to fenix | Supported legacy values normalize as documented; malformed values return 422 |
| Model fallback | A fenix/pro request could be retried as turbo when pro execution was unavailable | The selected effective model is preserved; fenix/pro is not automatically downgraded to turbo |
| Continue position | A negative continue_at could pass the old DTO | Values must be finite and >= 0; normalize legacy data before migration |
| Legacy identity fields | Owner and execution-provider identifiers could be populated | identity, uid, openid, and comparable compatibility identifiers are empty or redacted |
| Lyrics timeout | Could return running without a public recovery route | Returns an error with canonical task recovery details |
| Timeline failure | Could return HTTP 200 with an empty body | Returns a structured error |
| WAV failure | Could be surfaced as an empty or unavailable URL | A successful response always contains a URL |
/v1/info | Package rows and internal legacy data | OmnAPI credit-account view; package rows and key secrets are not recreated |
| Error body | Nest-era error shape | OmnAPI { success, error } envelope |
Two-phase migration plan
Section titled “Two-phase migration plan”Phase 0 — inventory and data ownership
Section titled “Phase 0 — inventory and data ownership”- Inventory calls to the exact nine covered paths. Route every other path to a product redesign instead of assuming compatibility.
- Record which stored values are resource
id, clipmid, legacytaskId, or business IDs. - Split historical clips from clips that will be created after the cutover. Historical Suno Cloud rows are not copied automatically.
- Identify workflows that use an old clip for extend, upload-extend, cover, concatenate, stems, WAV, or lyric timeline, plus workflows that reuse an old Persona. Keep them on the old service until the corresponding creation provenance is migrated to the correct OmnAPI customer, or arrange a managed migration with support.
- A successful lookup through the compatibility or modern query endpoints is not a provenance backfill. Importing history must create customer-scoped task/resource records with the correct original operation; never grant ownership merely because a client supplied a clip ID.
Phase 1 — host and credential cutover
Section titled “Phase 1 — host and credential cutover”- Create an OmnAPI account, fund credits, and issue a scoped OmnAPI API key.
- Change the base host to
https://api.omnapi.comand replace the key value. Keep the oldapi-keyheader and/v1paths if that reduces client changes. - Add a unique
Idempotency-Keyto every write request. - Persist
mid,omnapiTaskId, andpollUrlfrom new responses. Stop usingtaskIdas a canonical poll key. - Send canary traffic for each write operation. Compare HTTP status, array vs object shape, clip count, non-null media URLs, and terminal task settlement.
- During the history transition, route a request according to where its source clip was created: old clips to the old service, OmnAPI clips to OmnAPI.
Phase 2 — modern API migration
Section titled “Phase 2 — modern API migration”- Move simple/custom music to
/api/v1/suno/songs. - Move extend/cover to
/api/v1/suno/clips/{clipId}/derive. - Move timeline and exports to clip resource endpoints.
- Replace
midslookup with/api/v1/suno/clips?ids=...; replace recent compatibility history with task listing. - Use generic
concat-musiconly where existing-clip concat is still needed. - Replace
/v1/inforeporting with dashboard balance, usage export, and task settlement fields. - Remove dependencies on compatibility-only fields, then switch the header to
x-api-keyand remove/v1code paths.
Canary, rollback, and acceptance checks
Section titled “Canary, rollback, and acceptance checks”Before raising traffic, verify all of the following:
- Both generated clip
midvalues can be looked up and downloaded. omnapiTaskIdreaches a terminal state and matches the compatibility result.- Required credits and final charged/refunded credits reconcile.
- Retries with the same idempotency key do not create duplicate tasks, including zero-credit lyrics tasks.
idsandmidsare not mixed in application storage.- Historical clip derivatives follow the intended old/new routing rule.
- Error handling covers
401,402,403,404,406,409,422,429,502,503, and504.
Keep rollback configuration-based: retain the old host and key separately, and route only historical or failing cohorts back. Never send an OmnAPI key to the old host or a Suno Cloud key to OmnAPI.