{
  "openapi": "3.1.0",
  "info": {
    "title": "Suno Gateway REST API",
    "version": "v1",
    "description": "Submit asynchronous Suno work — music generation, extension and lyrics — through a multi-account gateway. The gateway owns account selection, upstream credits, per-tier concurrency limits and routing. Your service owns customer logic; every submission returns a server-generated `taskId` you then poll or receive by callback.\n\n## Authentication\n\nEvery request must carry a service API key as a bearer token:\n\n```\nAuthorization: Bearer <SERVICE_API_KEY>\n```\n\nKeys are issued per calling service on the private admin dashboard (`:8090`, token-protected). Tasks are scoped to the issuing key: a service can only see its own `taskId`s — unknown ids and ids owned by other services both return `404`.\n\n## Response envelope\n\nEvery response — success or error — is wrapped in `{code, msg, data}`:\n\n| Field | Meaning |\n|---|---|\n| `code` | Always equal to the HTTP status code (`200` on success). |\n| `msg` | `\"success\"` on success; a human-readable reason on errors. |\n| `data` | The endpoint payload. Omitted on errors. |\n\n## Task statuses\n\nTasks are asynchronous. `record-info` and callbacks report one of:\n\n| Status | Terminal | Meaning |\n|---|---|---|\n| `PENDING` | no | Queued, routing, or being submitted. Lyrics stay here until terminal. |\n| `TEXT_SUCCESS` | no | Music: clip IDs exist; audio not yet streamable. |\n| `FIRST_SUCCESS` | no | Music: first track is streamable. |\n| `SUCCESS` | yes | Music: all tracks ready. Lyrics: `response.data[]` contains the generated variant. |\n| `GENERATE_AUDIO_FAILED` | yes | Music task failed; see `errorCode` / `errorMessage`. |\n| `GENERATE_LYRICS_FAILED` | yes | Lyrics task failed; see `errorCode` / `errorMessage`. |\n| `SENSITIVE_WORD_ERROR` | yes | Lyrics rejected for prohibited words. |\n| `CREATE_TASK_FAILED` | yes | Submission failed or its outcome is unknown. |\n\nPoll until a terminal status, then stop. Generation typically takes 1–3 minutes depending on model and upstream queue depth.\n\n## Callbacks\n\nCallbacks are **optional on every endpoint** — omitting one simply means you poll instead. Music callbacks use the stages `text`, `first`, and `complete`, or `error` on failure, with snake_case track fields. Each stage has a 15-second request timeout and up to three attempts. Lyrics callbacks send one `complete` or `error` payload with camelCase `taskId`. Each callback has a 15-second request timeout and up to three attempts. Polling by `taskId` remains the reliable result path.\n\n## Typical workflow\n\n1. `GET /api/v1/models` — pick a model `key` that has capacity.\n2. `POST /api/v1/generate` (or extend / lyrics) — receive `{code:200, msg:\"success\", data:{taskId}}`.\n3. Poll `GET /api/v1/generate/record-info?taskId=…`, or wait for the callback."
  },
  "servers": [
    {
      "url": "/",
      "description": "This gateway (same origin as the docs)"
    }
  ],
  "security": [
    {
      "ServiceBearer": []
    }
  ],
  "tags": [
    {
      "name": "Generation",
      "description": "Submit asynchronous music and lyrics work."
    },
    {
      "name": "Retrieval",
      "description": "Poll task state and discover capacity."
    },
    {
      "name": "Images",
      "description": "Generate images on the ChatGPT provider, as durable tasks or through the OpenAI-compatible synchronous endpoint."
    }
  ],
  "paths": {
    "/api/v1/generate": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "generateMusic",
        "summary": "Generate music from a text prompt",
        "description": "Submit a text-to-music generation. Each submission creates a new task and returns its `taskId` immediately; the result arrives via polling or callback.\n\nValidation:\n\n- `customMode`, `instrumental` and `model` are required.\n- `prompt` is required except for `customMode: true` + `instrumental: true`.\n- `customMode: true` requires non-empty `style` **and** `title`; `prompt`, when present, is then treated as lyrics text.\n- `callBackUrl` is optional — omit it to rely on polling only.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateRequest"
              },
              "examples": {
                "simple": {
                  "summary": "Simple description",
                  "value": {
                    "prompt": "a short upbeat whistling jingle",
                    "customMode": false,
                    "instrumental": false,
                    "model": "V5",
                    "callBackUrl": "https://my-service.example.com/suno/callback"
                  }
                },
                "custom": {
                  "summary": "Custom mode with style and lyrics",
                  "value": {
                    "customMode": true,
                    "instrumental": false,
                    "title": "Coastline",
                    "style": "dreamy synth-pop, female vocal",
                    "prompt": "[Verse 1]\nSalt in the air...",
                    "model": "V5_5",
                    "negativeTags": "metal, distortion"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                },
                "examples": {
                  "accepted": {
                    "value": {
                      "code": 200,
                      "msg": "success",
                      "data": {
                        "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Music generation stage",
                "description": "POSTed for `text`, `first`, and `complete`, or `error` on failure. Each request has a 15-second timeout and up to three attempts.",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/sounds": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "generateSounds",
        "summary": "Generate a sound effect or musical loop",
        "description": "Submit a Suno Sounds task. The captured upstream request uses `task: sound`, maps public model `V5` and sends loop, BPM, and key controls in `metadata.sound_configs`. It generates two short clips and uses the normal music polling/callback lifecycle. `grabLyrics` is accepted as a best-effort post-generation enrichment; it produces data only when the completed clip exposes lyrics suitable for the captured v3 alignment API and never fails otherwise successful audio.\n\nValidation:\n\n- `prompt` and `model` are required; prompt is limited to 500 characters.\n- Sounds currently support only `V5`.\n- `soundTempo`, when present, must be an integer from 1 through 300.\n- `soundKey` defaults to `Any`.\n- `soundLoop` and `grabLyrics` default to false.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateSoundsRequest"
              },
              "examples": {
                "oneShot": {
                  "value": {
                    "prompt": "a short cinematic thunderclap with distant rain",
                    "model": "V5"
                  }
                },
                "loop": {
                  "value": {
                    "prompt": "warm analog bass loop",
                    "model": "V5",
                    "soundLoop": true,
                    "soundTempo": 120,
                    "soundKey": "Cm"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Sound generation stage",
                "description": "Same staged `text` / `first` / `complete` / `error` contract as music generation.",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/add-instrumental": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "addInstrumental",
        "summary": "Add an instrumental arrangement to uploaded audio",
        "description": "Temporarily deferred. The upstream underpainting request requires a non-empty prompt and lyrics-project relationship, but the public sunoapi.org request does not provide the corresponding prompt. This gateway returns 501 rather than inventing that required value.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddInstrumentalRequest"
              },
              "example": {
                "uploadUrl": "https://cdn.example.com/vocals.mp3",
                "title": "Night Drive",
                "tags": "deep house, atmospheric synths",
                "negativeTags": "metal",
                "callBackUrl": "https://my-service.example.com/suno/callback",
                "model": "V4_5PLUS"
              }
            }
          }
        },
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "501": {
            "description": "Deferred until the required upstream prompt mapping is verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/add-vocals": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "addVocals",
        "summary": "Add vocals to uploaded audio",
        "description": "Downloads `uploadUrl`, completes Suno's captured metadata, description-acceptance, and lyrics-project preparation, then submits `task: overpainting` with `metadata.is_remix: true`. `prompt` is sent as the custom-mode vocal prompt and `style` as tags. `model` defaults to `V4_5PLUS`. `vocalGender`, `styleWeight`, `weirdnessConstraint`, and `audioWeight` are accepted but currently ignored until their upstream representation is captured.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddVocalsRequest"
              },
              "example": {
                "uploadUrl": "https://cdn.example.com/instrumental.mp3",
                "prompt": "[Verse] Sing softly over the midnight rhythm",
                "title": "Night Drive",
                "style": "deep house, intimate female vocal",
                "negativeTags": "metal",
                "callBackUrl": "https://my-service.example.com/suno/callback",
                "model": "V4_5PLUS"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Add-vocals generation stage",
                "description": "Staged `text`, `first`, `complete`, or `error` music callback.",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/upload-cover": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "uploadCover",
        "summary": "Cover uploaded audio",
        "description": "Downloads `uploadUrl`, completes the captured metadata, description-acceptance, and lyrics-project preparation, then submits `task: cover`. Custom vocal mode sends exact lyrics/style/title and the prepared lyrics-project ID. Custom instrumental mode omits that ID. Non-custom mode uses the captured `SIMPLE_REMIX` payload with source lyrics in `prompt`, the caller description in `gpt_description_prompt`, and `override_fields: [\"prompt\"]`. Persona, weight, vocal-gender, and duration controls are accepted but currently ignored until captured.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadCoverRequest"
              },
              "examples": {
                "customVocal": {
                  "value": {
                    "uploadUrl": "https://cdn.example.com/source.mp3",
                    "prompt": "[Verse] Exact lyrics",
                    "style": "jazz",
                    "title": "Midnight Cover",
                    "customMode": true,
                    "instrumental": false,
                    "model": "V5",
                    "callBackUrl": "https://my-service.example.com/suno/callback"
                  }
                },
                "simple": {
                  "value": {
                    "uploadUrl": "https://cdn.example.com/source.mp3",
                    "prompt": "Turn this into a relaxed jazz arrangement",
                    "customMode": false,
                    "instrumental": false,
                    "model": "V5",
                    "callBackUrl": "https://my-service.example.com/suno/callback"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Upload-cover generation stage",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/upload-extend": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "uploadExtend",
        "summary": "Extend uploaded audio",
        "description": "Downloads and fully prepares `uploadUrl`, then submits the captured custom `task: upload_extend` flow with `continue_clip_id`, `metadata.is_remix`, `metadata.lyrics_updated`, and the prepared lyrics-project ID. `defaultParamFlag: true` requires style, title, and a positive `continueAt`. `defaultParamFlag: false` is temporarily rejected because it means inherit source parameters, not Simple mode, and its exact continuation policy is not yet verified. Persona, vocal-gender, and weight controls are accepted but currently ignored.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadExtendRequest"
              },
              "examples": {
                "custom": {
                  "value": {
                    "uploadUrl": "https://cdn.example.com/source.mp3",
                    "defaultParamFlag": true,
                    "prompt": "[Verse] Continue these lyrics",
                    "style": "jazz",
                    "title": "Longer Night",
                    "continueAt": 25,
                    "model": "V5",
                    "callBackUrl": "https://my-service.example.com/suno/callback"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Upload-extend generation stage",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/extend": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "extendMusic",
        "summary": "Extend a clip previously created through this gateway",
        "description": "Continue a clip created through this gateway. The source account is reused automatically.\n\nParameter modes:\n\n- `defaultParamFlag: false` inherits the source prompt, style, title, instrumental setting, negative tags, and extends from its recorded duration.\n- `defaultParamFlag: true` uses custom parameters and requires `continueAt`, `style`, and `title`; `prompt` is required for vocals and must be omitted for instrumentals.\n- `audioId`, `model`, and `defaultParamFlag` are required. The model must match the source clip.\n- `callBackUrl` is optional.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExtendRequest"
              },
              "examples": {
                "inheritSource": {
                  "summary": "Inherit source parameters and continue from its duration",
                  "value": {
                    "defaultParamFlag": false,
                    "audioId": "95363029-a760-4a9a-98e7-33dbadc07be0",
                    "model": "V5"
                  }
                },
                "custom": {
                  "summary": "Continue from second 30.5 with custom parameters",
                  "value": {
                    "defaultParamFlag": true,
                    "instrumental": false,
                    "audioId": "95363029-a760-4a9a-98e7-33dbadc07be0",
                    "model": "V5",
                    "continueAt": 30.5,
                    "prompt": "[Verse]\nContinue the story...",
                    "style": "dreamy synth-pop",
                    "title": "Coastline Continued"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                },
                "examples": {
                  "accepted": {
                    "value": {
                      "code": 200,
                      "msg": "success",
                      "data": {
                        "taskId": "e2f5c8a1-91d2-4b7e-8f03-2a6d9c4e1b57"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Music extension stage",
                "description": "Same staged `text` / `first` / `complete` / `error` contract as music generation.",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lyrics": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "generateLyrics",
        "summary": "Generate lyrics without submitting a music generation",
        "description": "Generate lyrics only—no music submission. The prompt is required and limited to 200 characters. `callBackUrl` is optional; omit it to poll with `GET /api/v1/lyrics/record-info`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LyricsRequest"
              },
              "examples": {
                "theme": {
                  "value": {
                    "prompt": "bittersweet summer song about a coastal town"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                },
                "examples": {
                  "accepted": {
                    "value": {
                      "code": 200,
                      "msg": "success",
                      "data": {
                        "taskId": "3f8c1d02-6a94-47be-9e51-c40b7f2d8a13"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Lyrics completion or failure",
                "description": "POSTed once as `complete`, or `error` on failure. Each request has a 15-second timeout and up to three attempts.",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/LyricsCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/record-info": {
      "get": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "musicRecordInfo",
        "summary": "Poll a music task by taskId",
        "description": "Fetch the current state of a music generation or extension task. One submission yields two tracks; both are listed in `response.sunoData` once the status is `SUCCESS`.\n\nUnknown `taskId`s and tasks owned by other services both return `404` — the gateway never reveals whether another service's task exists.",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "description": "Task id returned by a submit endpoint.",
            "schema": {
              "type": "string"
            },
            "example": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999"
          }
        ],
        "responses": {
          "200": {
            "description": "Task state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordInfoEnvelope"
                },
                "examples": {
                  "success": {
                    "summary": "Completed task with two tracks",
                    "value": {
                      "code": 200,
                      "msg": "success",
                      "data": {
                        "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999",
                        "status": "SUCCESS",
                        "type": "GENERATE",
                        "param": "{\"customMode\":false,\"instrumental\":false,\"prompt\":\"a short upbeat whistling jingle\"}",
                        "response": {
                          "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999",
                          "sunoData": [
                            {
                              "id": "95363029-a760-4a9a-98e7-33dbadc07be0",
                              "title": "",
                              "audioUrl": "https://gateway.example.com/api/v1/media/95363029-a760-4a9a-98e7-33dbadc07be0",
                              "streamAudioUrl": "https://gateway.example.com/api/v1/media/95363029-a760-4a9a-98e7-33dbadc07be0",
                              "imageUrl": "https://cdn2.suno.ai/image_95363029-a760-4a9a-98e7-33dbadc07be0.jpeg",
                              "modelName": "V5"
                            },
                            {
                              "id": "858af1e2-e288-45a6-846c-24f1409a432e",
                              "title": "",
                              "audioUrl": "https://gateway.example.com/api/v1/media/858af1e2-e288-45a6-846c-24f1409a432e",
                              "streamAudioUrl": "https://gateway.example.com/api/v1/media/858af1e2-e288-45a6-846c-24f1409a432e",
                              "imageUrl": "https://cdn2.suno.ai/image_858af1e2-e288-45a6-846c-24f1409a432e.jpeg",
                              "modelName": "V5"
                            }
                          ]
                        },
                        "errorCode": null,
                        "errorMessage": null
                      }
                    }
                  },
                  "pending": {
                    "summary": "Still running",
                    "value": {
                      "code": 200,
                      "msg": "success",
                      "data": {
                        "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999",
                        "status": "TEXT_SUCCESS",
                        "type": "GENERATE",
                        "param": "{\"customMode\":false,\"instrumental\":false,\"prompt\":\"a short upbeat whistling jingle\"}",
                        "response": {
                          "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999",
                          "sunoData": []
                        },
                        "errorCode": null,
                        "errorMessage": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/lyrics/record-info": {
      "get": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "lyricsRecordInfo",
        "summary": "Poll a lyrics task by taskId",
        "description": "Fetch the current state of a lyrics task. `response.data` is empty while no result exists and contains the generated lyrics variant on success. The current upstream integration produces one variant and does not provide a title, so `title` is an empty string.",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "description": "Task id returned by POST /api/v1/lyrics.",
            "schema": {
              "type": "string"
            },
            "example": "3f8c1d02-6a94-47be-9e51-c40b7f2d8a13"
          }
        ],
        "responses": {
          "200": {
            "description": "Task state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecordInfoEnvelope"
                },
                "examples": {
                  "textSuccess": {
                    "value": {
                      "code": 200,
                      "msg": "success",
                      "data": {
                        "taskId": "3f8c1d02-6a94-47be-9e51-c40b7f2d8a13",
                        "status": "SUCCESS",
                        "type": "LYRICS",
                        "param": "{\"prompt\":\"bittersweet summer song about a coastal town\"}",
                        "response": {
                          "taskId": "3f8c1d02-6a94-47be-9e51-c40b7f2d8a13",
                          "data": [
                            {
                              "text": "[Verse 1]\nSalt in the air...",
                              "title": "",
                              "status": "complete",
                              "errorMessage": ""
                            }
                          ]
                        },
                        "errorCode": null,
                        "errorMessage": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/generate/get-timestamped-lyrics": {
      "post": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "getTimestampedLyrics",
        "summary": "Get word-level lyric timings for a generated track",
        "description": "Read timestamped lyrics for a clip created by the specified task. The task and clip must belong to the calling service. The gateway sends the captured `POST /aligned_lyrics/v3` request with the clip's exact lyrics and polls the same endpoint when state is `running`; instrumental tracks return empty arrays without an upstream call. Suno v3 does not return the public flat `waveformData`, `hootCer`, or `isStreamed` fields, so those currently remain `[]`, `0`, and `false` respectively until that adapter mapping is verified.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimestampedLyricsRequest"
              },
              "example": {
                "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999",
                "audioId": "e2319d75-3dc5-43a5-9c2e-99498cadc7dc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Timestamped lyrics, or an empty word list for an instrumental track.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimestampedLyricsEnvelope"
                },
                "example": {
                  "code": 200,
                  "msg": "success",
                  "data": {
                    "alignedWords": [
                      {
                        "word": "Morning ",
                        "success": true,
                        "startS": 1.58,
                        "endS": 3.16,
                        "palign": 0.99
                      }
                    ],
                    "waveformData": [
                      0.08,
                      0.06
                    ],
                    "hootCer": 0.12,
                    "isStreamed": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "description": "The owning upstream account could not return lyric timings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/vocal-removal/generate": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "separateVocalsFromMusic",
        "summary": "Separate vocals or instrument stems",
        "description": "Submits Suno’s captured `task: gen_stem` flow. `separate_vocal` extracts Lead Vocal, `split_stem` uses the captured Twelve mode, and `split_stem_advanced` forwards the selected `stemName`. Existing gateway clips retain account affinity; `audioUrl` is downloaded with SSRF protection, limited to 20 MB, and initialized through the shared upload pipeline. Stem extraction reserves 50 upstream credits.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VocalRemovalGenerateRequest"
              },
              "examples": {
                "separateExisting": {
                  "value": {
                    "taskId": "source-task-id",
                    "audioId": "source-clip-id",
                    "type": "separate_vocal",
                    "callBackUrl": "https://example.com/callback"
                  }
                },
                "advancedUpload": {
                  "value": {
                    "audioUrl": "https://cdn.example.com/source.mp3",
                    "type": "split_stem_advanced",
                    "stemName": "Bass",
                    "callBackUrl": "https://example.com/callback"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Source task or audio not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "vocalRemovalGenerated": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Vocal removal completion",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/VocalRemovalCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/vocal-removal/record-info": {
      "get": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "getVocalSeparationDetails",
        "summary": "Get vocal separation details",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Task ID returned by vocal-removal/generate."
          }
        ],
        "responses": {
          "200": {
            "description": "Task state and separated tracks.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VocalRemovalRecordInfoEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Task not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/midi/generate": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "generateMidi",
        "summary": "Generate MIDI from separated audio",
        "description": "Starts MIDI extraction by polling Suno’s captured `GET /api/gen/{stemId}/midi` flow. The source vocal-removal task must be complete. `audioId` selects one originData track; when omitted, all separated tracks are processed and their instrument arrays are merged in source order.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MidiGenerateRequest"
              },
              "example": {
                "taskId": "vocal-removal-task-id",
                "audioId": "separated-track-id",
                "callBackUrl": "https://example.com/callback"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Vocal-removal task not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "midiGenerated": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "MIDI completion",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MidiCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/midi/record-info": {
      "get": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "getMidiDetails",
        "summary": "Get MIDI generation details",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "MIDI task state and note data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MidiRecordInfoEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Task not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/suno/cover/generate": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "generateCoverArt",
        "summary": "Generate music cover artwork",
        "description": "Temporarily deferred. The public request provides only `taskId`, while the captured upstream image request requires a prompt and Suno's live modal starts with an empty prompt. The gateway returns 501 rather than deriving or inventing a prompt. Record-info remains available for previously persisted cover-art tasks.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CoverArtGenerateRequest"
              },
              "example": {
                "taskId": "completed-music-task-id",
                "callBackUrl": "https://example.com/callback"
              }
            }
          }
        },
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "501": {
            "description": "Deferred until the required upstream prompt mapping is verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/suno/cover/record-info": {
      "get": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "getCoverArtDetails",
        "summary": "Get cover artwork generation details",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Cover task ID returned by suno/cover/generate."
          }
        ],
        "responses": {
          "200": {
            "description": "Cover task state and generated image URLs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoverArtRecordInfoEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Task not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/mashup": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "generateMashup",
        "summary": "Generate a music mashup",
        "description": "Downloads exactly two public source audio URLs with SSRF protection and a 100 MiB limit per source, fully prepares both through one selected Suno account, then submits the captured `task: mashup_condition` flow. Custom vocal and custom instrumental V5 are verified. Non-custom and non-V5 variants are temporarily rejected. Duration, vocal-gender, and weight controls are accepted but currently ignored until captured.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MashupGenerateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "mashupGenerated": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Mashup generation progress or completion",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/generate/generate-persona": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "generatePersona",
        "summary": "Create a persona from a generated clip",
        "description": "Synchronous: creates a Suno persona (POST /api/persona/create/) from the source clip's vocals and returns {personaId, name} directly. No job and no callback; not pollable.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GeneratePersonaRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "taskId": "b3c2c9f1-3c2c-4f1a-9f2b-1234567890ab",
                    "audioId": "a1b2c3d4-1111-2222-3333-444455556666",
                    "name": "Midnight Voice",
                    "description": "Soft female vocals"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persona created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PersonaEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/generate/replace-section": {
      "post": {
        "tags": [
          "Generation"
        ],
        "operationId": "replaceSection",
        "summary": "Replace a section of a song (infill)",
        "description": "Two reference modes: (1) taskId + audioId replaces a section of an existing gateway clip; (2) uploadUrl + model replaces a section of uploaded audio. Runs the captured v2-web infill payload with context lyrics derived from aligned lyrics when available. The replaced window must be at least 10 seconds.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceSectionRequest"
              },
              "examples": {
                "existingClip": {
                  "value": {
                    "taskId": "b3c2c9f1-3c2c-4f1a-9f2b-1234567890ab",
                    "audioId": "a1b2c3d4-1111-2222-3333-444455556666",
                    "prompt": "[Verse] New section lyrics",
                    "tags": "jazz, lo-fi",
                    "title": "Midnight Drive (reworked)",
                    "negativeTags": "metal",
                    "infillStartS": 45,
                    "infillEndS": 70,
                    "fullLyrics": "[Verse 1] old words\\n[Verse 2] more words"
                  }
                },
                "uploadedAudio": {
                  "value": {
                    "uploadUrl": "https://cdn.example.com/source.mp3",
                    "model": "V5",
                    "prompt": "[Verse] New section lyrics",
                    "tags": "jazz",
                    "title": "Reworked",
                    "infillStartS": 10,
                    "infillEndS": 30,
                    "fullLyrics": "old lyrics"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "taskCompleted": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Replace-section completion callback",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/MusicCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models": {
      "get": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "listModels",
        "summary": "List models currently backed by at least one usable account",
        "description": "Use `key` as the `model` value on submit endpoints. Standard models are returned as public aliases; unknown or custom models retain their raw key.",
        "responses": {
          "200": {
            "description": "Available models.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelsEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "code": 200,
                      "msg": "success",
                      "data": {
                        "models": [
                          {
                            "key": "V5",
                            "label": "v5",
                            "accountCount": 1
                          },
                          {
                            "key": "V5_5",
                            "label": "v5.5",
                            "accountCount": 1
                          },
                          {
                            "key": "V4_5ALL",
                            "label": "v4.5-all",
                            "accountCount": 2
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/wav/generate": {
      "post": {
        "tags": [
          "Conversion"
        ],
        "operationId": "convertToWav",
        "summary": "Convert a generated track to WAV format",
        "description": "Submit a WAV export for a clip previously created through this gateway. The source `taskId` and `audioId` must belong to the calling service, and the audio must have been created by that task. `callBackUrl` is required and receives a single completion notification carrying `audioWavUrl`.\n\nUpstream mapping: `POST /api/gen/{clipId}/convert_wav/` (HTTP 204), then the signed URL is read from `GET /api/gen/{clipId}/wav_file/`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WavGenerateRequest"
              },
              "example": {
                "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999",
                "audioId": "e2319d75-3dc5-43a5-9c2e-99498cadc7dc",
                "callBackUrl": "https://my-service.example.com/suno/wav-callback"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Conversion accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "callbacks": {
          "wavGenerated": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "WAV conversion completion",
                "description": "Sent once when the export completes, carrying the signed WAV download URL.",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/WavCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/wav/record-info": {
      "get": {
        "tags": [
          "Conversion"
        ],
        "operationId": "getWavConversionDetails",
        "summary": "Poll a WAV conversion task",
        "description": "Fetch the state of a WAV conversion created by `POST /api/v1/wav/generate`. The task must belong to the calling service.",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "description": "Task id returned by the WAV generate endpoint.",
            "schema": {
              "type": "string"
            },
            "example": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c"
          }
        ],
        "responses": {
          "200": {
            "description": "WAV conversion state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WavRecordInfoEnvelope"
                },
                "example": {
                  "code": 200,
                  "msg": "success",
                  "data": {
                    "taskId": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c",
                    "musicId": "8551c8ac-662c-4a0f-b1c4-2e8f9d1a3b7c",
                    "musicIndex": 0,
                    "callbackUrl": "https://api.example.com/callback",
                    "completeTime": "2025-01-01 00:10:00",
                    "response": {
                      "audioWavUrl": "https://example.com/s/04e6c8ace727.wav"
                    },
                    "successFlag": "SUCCESS",
                    "createTime": "2025-01-01 00:00:00",
                    "errorCode": null,
                    "errorMessage": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/mp4/generate": {
      "post": {
        "tags": [
          "Conversion"
        ],
        "operationId": "createMusicVideo",
        "summary": "Create a music video for a generated track",
        "description": "Submit a music-video render for a clip previously created through this gateway. The source `taskId` and `audioId` must belong to the calling service, and the audio must have been created by that task. `callBackUrl` is required and receives a single completion notification carrying `video_url`.\n\nUpstream mapping: `POST /api/video/generate/{clipId}/` with an empty body (HTTP 204), then `GET /api/video/generate/{clipId}/status/` returns `{\"status\":\"processing\"}` until it returns `{\"status\":\"complete\",\"video_url\":\"...\"}`. `author` and `domainName` are accepted for reference compatibility but are not forwarded upstream (the captured create request has an empty body).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Mp4GenerateRequest"
              },
              "example": {
                "taskId": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999",
                "audioId": "e2319d75-3dc5-43a5-9c2e-99498cadc7dc",
                "callBackUrl": "https://my-service.example.com/suno/mp4-callback"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Render accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "callbacks": {
          "mp4Generated": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Music video completion",
                "description": "Sent once when the render completes, carrying the signed MP4 URL.",
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/Mp4CallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback acknowledged."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/mp4/record-info": {
      "get": {
        "tags": [
          "Conversion"
        ],
        "operationId": "getMusicVideoDetails",
        "summary": "Poll a music-video render task",
        "description": "Fetch the state of a music-video render created by `POST /api/v1/mp4/generate`. The task must belong to the calling service.",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "description": "Task id returned by the MP4 generate endpoint.",
            "schema": {
              "type": "string"
            },
            "example": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c"
          }
        ],
        "responses": {
          "200": {
            "description": "Music-video render state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mp4RecordInfoEnvelope"
                },
                "example": {
                  "code": 200,
                  "msg": "success",
                  "data": {
                    "taskId": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c",
                    "musicId": "8551c8ac-662c-4a0f-b1c4-2e8f9d1a3b7c",
                    "musicIndex": 0,
                    "callbackUrl": "https://api.example.com/callback",
                    "completeTime": "2025-01-01 00:10:00",
                    "response": {
                      "videoUrl": "https://example.com/videos/video_847715e66259.mp4"
                    },
                    "successFlag": "SUCCESS",
                    "createTime": "2025-01-01 00:00:00",
                    "errorCode": null,
                    "errorMessage": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/media/{clipId}": {
      "get": {
        "tags": [
          "Retrieval"
        ],
        "operationId": "getClipMedia",
        "summary": "Stream a generated clip's audio as MP3",
        "description": "The audio origin behind every `audioUrl`/`streamAudioUrl`. Suno stopped serving clip audio in the clear, so this route fetches the encrypted rendition through the account that generated the clip, decrypts it and streams the bytes.\n\nUnauthenticated by design: media players cannot send a bearer token, and the clip id is the only secret — clips this gateway did not create return 404.\n\nThe default rendition is **MP3** (`audio/mpeg`, 192 kbps CBR), transcoded live and never written to disk. It still carries an exact `Content-Length` and supports `Range`, because constant-bitrate MP3 has a predictable frame layout. The gateway keeps finished MP3 renditions in memory (`media.cache_size_mb`), so a clip is encoded once and every replay or seek is served from RAM; responses are `Cache-Control: public, max-age=3600` because a finished clip's audio is immutable.\n\n`?format=m4a` serves what Suno publishes instead: Opus in MP4 (`audio/mp4`, ~145 kbps), one lossy generation better and free of transcoding cost — use it when the player can read `audio/mp4`. A clip that is still rendering is delivered as chunked audio with no `Content-Length` and cannot be seeked.",
        "security": [],
        "parameters": [
          {
            "name": "clipId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Clip id from `RecordInfo.response.sunoData[].id`."
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "mp3",
                "m4a"
              ],
              "default": "mp3"
            },
            "description": "Omit (or `mp3`) for the transcoded MP3. `m4a` serves Suno's own Opus-in-MP4 rendition unchanged. An explicit `mp3` answers 501 when the gateway has no transcoder; the default falls back to `m4a` in that case."
          },
          {
            "name": "Range",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Single byte range, `bytes=<start>-` or `bytes=<start>-<end>`. Other forms are ignored and the whole clip is returned."
          }
        ],
        "responses": {
          "200": {
            "description": "The whole clip. `audio/mpeg` by default, `audio/mp4` with format=m4a.",
            "headers": {
              "Accept-Ranges": {
                "description": "`bytes` when the rendition can be seeked.",
                "schema": {
                  "type": "string"
                }
              },
              "Content-Disposition": {
                "description": "`inline` with a `<clipId>.<ext>` filename.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "audio/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/webm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "The requested byte range.",
            "headers": {
              "Content-Range": {
                "description": "`bytes <start>-<end>/<total>`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "audio/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/webm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Unsupported format.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "code": 400,
                      "msg": "format must be mp3 or m4a"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No clip with this id was generated by this gateway.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "code": 404,
                      "msg": "unknown clip"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The clip exists but has no playable audio yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "code": 409,
                      "msg": "audio is not ready yet"
                    }
                  }
                }
              }
            }
          },
          "416": {
            "description": "The requested range lies outside the clip, or the clip is still rendering and cannot be seeked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "code": 416,
                      "msg": "range is not satisfiable"
                    }
                  }
                }
              }
            }
          },
          "501": {
            "description": "`?format=mp3` was requested explicitly but this gateway has no transcoder. The default rendition falls back to m4a instead of failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "code": 501,
                      "msg": "mp3 delivery is not available on this gateway"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "Upstream did not deliver the audio.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "default": {
                    "value": {
                      "code": 502,
                      "msg": "upstream media unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/images/generate": {
      "post": {
        "tags": [
          "Images"
        ],
        "operationId": "generateImage",
        "summary": "Generate an image",
        "description": "Submit an image generation to the ChatGPT provider. The prompt is the whole request: the upstream consumer surface exposes no size, quality or format controls, so `model` is accepted for client compatibility and ignored.\n\nReturns 503 when the gateway is deployed without `chatgpt.solver_path`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImageGenerateRequest"
              },
              "example": {
                "prompt": "High quality AirPods Pro on a white background, photorealistic",
                "callBackUrl": "https://my-service.example.com/suno/image-callback"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generation accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/QueueUnavailable"
          }
        },
        "callbacks": {
          "imageGenerated": {
            "{$request.body#/callBackUrl}": {
              "post": {
                "summary": "Image generation completed",
                "requestBody": {
                  "required": true,
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/ImageCallbackEnvelope"
                      }
                    }
                  }
                },
                "responses": {
                  "200": {
                    "description": "Callback accepted."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/images/record-info": {
      "get": {
        "tags": [
          "Images"
        ],
        "operationId": "getImageDetails",
        "summary": "Poll an image generation task",
        "description": "Fetch the state of an image generation created by `POST /api/v1/images/generate`. The task must belong to the calling service.",
        "parameters": [
          {
            "name": "taskId",
            "in": "query",
            "required": true,
            "description": "Task id returned by the image generate endpoint.",
            "schema": {
              "type": "string"
            },
            "example": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c"
          }
        ],
        "responses": {
          "200": {
            "description": "Image generation state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageRecordInfoEnvelope"
                },
                "example": {
                  "code": 200,
                  "msg": "success",
                  "data": {
                    "taskId": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c",
                    "status": "SUCCESS",
                    "param": "{\"prompt\":\"a red bicycle on a beach\"}",
                    "response": {
                      "taskId": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c",
                      "imageUrl": "https://gateway.example.com/api/v1/images/file/988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c",
                      "mimeType": "image/png",
                      "sizeBytes": 1841233
                    },
                    "errorCode": null,
                    "errorMessage": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/images/file/{taskId}": {
      "get": {
        "tags": [
          "Images"
        ],
        "operationId": "downloadImage",
        "summary": "Download a generated image",
        "description": "Stream the generated image bytes. This route is deliberately unauthenticated and addressed by the unguessable task UUID, because an `<img src>` and an OpenAI SDK `url` consumer cannot attach a bearer token. Range and conditional requests are supported.\n\nFiles are retained for `chatgpt.image_retention` (default 7 days) after generation and then deleted; this route answers 404 afterwards while the task record stays readable. Download promptly or copy the bytes to your own storage.",
        "security": [],
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "description": "Task id of a succeeded image generation.",
            "schema": {
              "type": "string"
            },
            "example": "988e5b84-c8d3-4a0f-b1c4-2e8f9d1a3b7c"
          }
        ],
        "responses": {
          "200": {
            "description": "Image bytes.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/images/generations": {
      "post": {
        "tags": [
          "Images"
        ],
        "operationId": "createImageGeneration",
        "summary": "Generate images (OpenAI-compatible, synchronous)",
        "description": "OpenAI Images-compatible endpoint over the same durable pipeline: point an existing OpenAI SDK at `base_url=<gateway>/api/v1`. The call blocks until every image is terminal, up to `chatgpt.direct_timeout`, then returns `b64_json` (default) or a gateway-hosted `url`.\n\nOn a 504 the jobs keep running and stay retrievable through `GET /api/v1/images/record-info`. Errors use OpenAI's envelope, not this gateway's `{code,msg}` envelope.\n\n`model`, `size`, `quality`, `background`, `output_format`, `output_compression`, `moderation`, `partial_images`, `style` and `user` are accepted for SDK compatibility and ignored: the ChatGPT consumer conversation exposes none of them. `stream` is rejected. `/v1/images/edits` and `/v1/images/variations` are not implemented.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenAIImageGenerationRequest"
              },
              "example": {
                "model": "gpt-image-1",
                "prompt": "a red bicycle on a beach, photorealistic",
                "n": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated images.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIImagesResponse"
                },
                "example": {
                  "created": 1767225600,
                  "data": [
                    {
                      "b64_json": "iVBORw0KGgoAAAANSUhEUg..."
                    }
                  ],
                  "output_format": "png"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid service token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Upstream rate limited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Image generation is not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIErrorResponse"
                }
              }
            }
          },
          "504": {
            "description": "Still running; poll the task API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenAIErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ServiceBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Paste a service API key. Requests use `Authorization: Bearer YOUR_KEY`. Keys are issued per calling service on the private admin dashboard."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "missingFields": {
                "value": {
                  "code": 400,
                  "msg": "prompt and model are required"
                }
              },
              "customMode": {
                "value": {
                  "code": 400,
                  "msg": "custom mode requires style and title"
                }
              },
              "customModePrompt": {
                "value": {
                  "code": 400,
                  "msg": "custom mode requires a prompt"
                }
              },
              "negativeContinueAt": {
                "value": {
                  "code": 400,
                  "msg": "continueAt cannot be negative"
                }
              },
              "coverWindow": {
                "value": {
                  "code": 400,
                  "msg": "startS and endS must be supplied together"
                }
              },
              "coverWindowOrder": {
                "value": {
                  "code": 400,
                  "msg": "endS must be after startS"
                }
              },
              "missingTaskId": {
                "value": {
                  "code": 400,
                  "msg": "taskId is required"
                }
              },
              "badJson": {
                "value": {
                  "code": 400,
                  "msg": "invalid JSON body: unexpected EOF"
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid service token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "default": {
                "value": {
                  "code": 401,
                  "msg": "missing or invalid service token"
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Unknown taskId, or owned by another service.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "default": {
                "value": {
                  "code": 404,
                  "msg": "task not found"
                }
              }
            }
          }
        }
      },
      "QueueUnavailable": {
        "description": "Task persisted but the queue is temporarily unavailable; poll by taskId after retrying. The task still runs once the queue recovers — do not blindly resubmit.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "default": {
                "value": {
                  "code": 503,
                  "msg": "task persisted but the queue is temporarily unavailable; poll by taskId after retrying"
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      }
    },
    "schemas": {
      "GenerateRequest": {
        "type": "object",
        "required": [
          "customMode",
          "instrumental",
          "model"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "description": "Free-form description of the song. Required except when customMode and instrumental are both true. In custom mode this is the lyrics text instead.",
            "example": "a short upbeat whistling jingle"
          },
          "model": {
            "type": "string",
            "description": "Model `key` from `GET /api/v1/models`, such as `V4`, `V4_5`, `V4_5PLUS`, `V4_5ALL`, `V5`, or `V5_5`.",
            "example": "V5"
          },
          "customMode": {
            "type": "boolean",
            "description": "Required. When true, `style` and `title` become required, and `prompt` is treated as lyrics text when not instrumental."
          },
          "style": {
            "type": "string",
            "description": "Style/genre tags. Required when `customMode` is true.",
            "example": "dreamy synth-pop, female vocal"
          },
          "title": {
            "type": "string",
            "description": "Track title. Required when `customMode` is true.",
            "example": "Coastline"
          },
          "instrumental": {
            "type": "boolean",
            "description": "Required. Generate without vocals. In custom instrumental mode, `prompt` may be omitted."
          },
          "negativeTags": {
            "type": "string",
            "description": "Comma-separated tags to steer away from.",
            "example": "metal, distortion"
          },
          "callBackUrl": {
            "type": "string",
            "description": "Optional URL receiving one POST of the final record-info shape. Omit to use polling only.",
            "example": "https://my-service.example.com/suno/callback"
          },
          "personaId": {
            "type": "string",
            "description": "Only available when custom parameters are enabled. Persona ID to apply to the generated music. Optional. Use a persona created via POST /api/v1/generate/generate-persona."
          },
          "personaModel": {
            "type": "string",
            "description": "Persona model type to apply when using personaId. `style_persona` (default) for personas from Generate Persona; `voice_persona` for voice personas."
          },
          "duration": {
            "type": "integer",
            "description": "Audio duration in seconds. Optional. Only supported when model is V5_5 and customMode is true. Range: 10-360 seconds."
          },
          "vocalGender": {
            "type": "string",
            "description": "Preferred vocal gender. Allowed values: 'm' (male), 'f' (female)."
          },
          "styleWeight": {
            "type": "number",
            "format": "double",
            "description": "Weight of the provided style guidance. Range 0.00-1.00."
          },
          "weirdnessConstraint": {
            "type": "number",
            "format": "double",
            "description": "Constraint on creative deviation/novelty. Range 0.00-1.00."
          },
          "audioWeight": {
            "type": "number",
            "format": "double",
            "description": "Weight of the input audio influence (where applicable). Range 0.00-1.00."
          }
        }
      },
      "GenerateSoundsRequest": {
        "type": "object",
        "required": [
          "prompt",
          "model"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500,
            "description": "Description of the desired sound effect or loop."
          },
          "model": {
            "type": "string",
            "enum": [
              "V5"
            ],
            "description": "Sounds currently support only V5."
          },
          "soundLoop": {
            "type": "boolean",
            "default": false,
            "description": "Generate a seamlessly loopable sound."
          },
          "soundTempo": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 300,
            "description": "Optional BPM; omit or use null for Auto."
          },
          "soundKey": {
            "type": "string",
            "default": "Any",
            "enum": [
              "Any",
              "Cm",
              "C#m",
              "Dm",
              "D#m",
              "Em",
              "Fm",
              "F#m",
              "Gm",
              "G#m",
              "Am",
              "A#m",
              "Bm",
              "C",
              "C#",
              "D",
              "D#",
              "E",
              "F",
              "F#",
              "G",
              "G#",
              "A",
              "A#",
              "B"
            ]
          },
          "grabLyrics": {
            "type": "boolean",
            "default": false,
            "description": "Best-effort v3 alignment when a completed sound clip exposes lyrics. Accepted but has no effect for clips with no lyric text."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "description": "Optional callback URL receiving staged sound callbacks."
          }
        }
      },
      "AddInstrumentalRequest": {
        "type": "object",
        "required": [
          "uploadUrl",
          "title",
          "tags",
          "negativeTags"
        ],
        "properties": {
          "uploadUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "Publicly reachable HTTP(S) audio URL. Private and loopback destinations are rejected."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "Title for the generated track."
          },
          "tags": {
            "type": "string",
            "minLength": 1,
            "description": "Desired style, mood, and instrumental characteristics."
          },
          "negativeTags": {
            "type": "string",
            "description": "Styles or traits to exclude. The key is required; an empty value is allowed."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "URL receiving staged music callbacks."
          },
          "model": {
            "type": "string",
            "default": "V4_5PLUS",
            "description": "Generation model. Defaults to V4_5PLUS."
          },
          "vocalGender": {
            "type": "string",
            "description": "Preferred vocal gender. Allowed values: 'm' (male), 'f' (female)."
          },
          "styleWeight": {
            "type": "number",
            "format": "double",
            "description": "Weight of the provided style guidance. Range 0.00-1.00."
          },
          "weirdnessConstraint": {
            "type": "number",
            "format": "double",
            "description": "Constraint on creative deviation/novelty. Range 0.00-1.00."
          },
          "audioWeight": {
            "type": "number",
            "format": "double",
            "description": "Weight of the input audio influence (where applicable). Range 0.00-1.00."
          }
        }
      },
      "AddVocalsRequest": {
        "type": "object",
        "required": [
          "uploadUrl",
          "prompt",
          "title",
          "style",
          "negativeTags"
        ],
        "properties": {
          "uploadUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "Publicly reachable HTTP(S) audio URL."
          },
          "prompt": {
            "type": "string",
            "minLength": 1,
            "description": "Vocal lyrics or instructions sent as the custom-mode prompt."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "Title for the generated track."
          },
          "style": {
            "type": "string",
            "minLength": 1,
            "description": "Music and vocal style sent as generation tags."
          },
          "negativeTags": {
            "type": "string",
            "description": "Styles or vocal traits to exclude. The key is required; an empty value is allowed."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "URL receiving staged music callbacks."
          },
          "model": {
            "type": "string",
            "default": "V4_5PLUS",
            "description": "Generation model. Defaults to V4_5PLUS."
          },
          "vocalGender": {
            "type": "string",
            "enum": [
              "m",
              "f"
            ],
            "description": "Compatibility field; currently accepted but ignored."
          },
          "styleWeight": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "weirdnessConstraint": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "audioWeight": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          }
        }
      },
      "UploadCoverRequest": {
        "type": "object",
        "required": [
          "uploadUrl",
          "customMode",
          "instrumental",
          "model"
        ],
        "properties": {
          "uploadUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "Publicly reachable HTTP(S) audio URL."
          },
          "prompt": {
            "type": "string",
            "description": "Required in non-custom mode and in custom vocal mode. Exact lyrics in custom mode; description in non-custom mode."
          },
          "style": {
            "type": "string",
            "description": "Required in custom mode; omit in non-custom mode."
          },
          "title": {
            "type": "string",
            "description": "Required in custom mode; omit in non-custom mode."
          },
          "customMode": {
            "type": "boolean",
            "description": "Select exact custom fields or a non-custom description prompt."
          },
          "instrumental": {
            "type": "boolean",
            "description": "Custom instrumental mode permits an empty prompt."
          },
          "model": {
            "type": "string",
            "minLength": 1,
            "description": "Generation model key."
          },
          "negativeTags": {
            "type": "string",
            "description": "Styles or traits to exclude."
          },
          "personaId": {
            "type": "string",
            "description": "Compatibility field; currently accepted but ignored."
          },
          "personaModel": {
            "type": "string",
            "enum": [
              "style_persona",
              "voice_persona"
            ],
            "description": "Compatibility field; currently accepted but ignored."
          },
          "vocalGender": {
            "type": "string",
            "enum": [
              "m",
              "f"
            ],
            "description": "Compatibility field; currently accepted but ignored."
          },
          "styleWeight": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "weirdnessConstraint": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "audioWeight": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "duration": {
            "type": "integer",
            "minimum": 10,
            "maximum": 360,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "URL receiving staged music callbacks."
          }
        }
      },
      "UploadExtendRequest": {
        "type": "object",
        "required": [
          "uploadUrl",
          "defaultParamFlag",
          "model"
        ],
        "properties": {
          "uploadUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "Publicly reachable HTTP(S) audio URL."
          },
          "defaultParamFlag": {
            "type": "boolean",
            "description": "True selects the captured custom flow. False means inherit source parameters and is temporarily rejected until its exact continuation policy is verified."
          },
          "instrumental": {
            "type": "boolean",
            "default": false
          },
          "prompt": {
            "type": "string",
            "description": "Optional extension prompt. Character limit depends on model."
          },
          "style": {
            "type": "string",
            "description": "Required in custom mode; omit in non-custom mode."
          },
          "title": {
            "type": "string",
            "description": "Required in custom mode; omit in non-custom mode."
          },
          "continueAt": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Required in custom mode; omit in non-custom mode."
          },
          "model": {
            "type": "string",
            "minLength": 1,
            "description": "Generation model key."
          },
          "negativeTags": {
            "type": "string",
            "description": "Styles or traits to exclude."
          },
          "personaId": {
            "type": "string",
            "description": "Compatibility field; currently accepted but ignored."
          },
          "personaModel": {
            "type": "string",
            "enum": [
              "style_persona",
              "voice_persona"
            ],
            "description": "Compatibility field; currently accepted but ignored."
          },
          "vocalGender": {
            "type": "string",
            "enum": [
              "m",
              "f"
            ],
            "description": "Compatibility field; currently accepted but ignored."
          },
          "styleWeight": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "weirdnessConstraint": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "audioWeight": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Compatibility field; currently accepted but ignored."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "URL receiving staged music callbacks."
          }
        }
      },
      "ExtendRequest": {
        "type": "object",
        "required": [
          "defaultParamFlag",
          "audioId",
          "model"
        ],
        "properties": {
          "defaultParamFlag": {
            "type": "boolean",
            "description": "False inherits the source parameters and duration. True uses the custom parameters in this request."
          },
          "instrumental": {
            "type": "boolean",
            "default": false,
            "description": "Custom mode only. When true, prompt must be omitted."
          },
          "audioId": {
            "type": "string",
            "description": "Source clip `id` from `response.sunoData[]`. It must belong to the calling service.",
            "example": "95363029-a760-4a9a-98e7-33dbadc07be0"
          },
          "prompt": {
            "type": "string",
            "description": "Custom lyrics. Required when defaultParamFlag is true and instrumental is false."
          },
          "style": {
            "type": "string",
            "description": "Custom style tags. Required when defaultParamFlag is true."
          },
          "title": {
            "type": "string",
            "description": "Custom title. Required when defaultParamFlag is true."
          },
          "continueAt": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Custom continuation position in seconds. Required when defaultParamFlag is true.",
            "example": 30.5
          },
          "model": {
            "type": "string",
            "description": "Model key or public alias; it must resolve to the source clip's model.",
            "example": "V5"
          },
          "negativeTags": {
            "type": "string",
            "description": "Custom styles or traits to exclude."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "description": "Optional callback URL receiving staged music callbacks. Omit to use polling only."
          },
          "personaId": {
            "type": "string",
            "description": "Only available when custom parameters are enabled. Persona ID to apply to the generated music. Optional. Use a persona created via POST /api/v1/generate/generate-persona."
          },
          "personaModel": {
            "type": "string",
            "description": "Persona model type to apply when using personaId. `style_persona` (default) for personas from Generate Persona; `voice_persona` for voice personas."
          },
          "vocalGender": {
            "type": "string",
            "description": "Preferred vocal gender. Allowed values: 'm' (male), 'f' (female)."
          },
          "styleWeight": {
            "type": "number",
            "format": "double",
            "description": "Weight of the provided style guidance. Range 0.00-1.00."
          },
          "weirdnessConstraint": {
            "type": "number",
            "format": "double",
            "description": "Constraint on creative deviation/novelty. Range 0.00-1.00."
          },
          "audioWeight": {
            "type": "number",
            "format": "double",
            "description": "Weight of the input audio influence (where applicable). Range 0.00-1.00."
          }
        }
      },
      "LyricsRequest": {
        "type": "object",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "maxLength": 200,
            "description": "Description of the desired theme, mood, style, and song structure.",
            "example": "bittersweet summer song about a coastal town"
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "description": "Optional URL receiving the final result once. Omit to poll instead."
          }
        }
      },
      "SubmitEnvelope": {
        "type": "object",
        "description": "Standard `{code, msg, data}` envelope; `data.taskId` identifies the accepted task.",
        "properties": {
          "code": {
            "type": "integer",
            "const": 200
          },
          "msg": {
            "type": "string",
            "const": "success"
          },
          "data": {
            "type": "object",
            "properties": {
              "taskId": {
                "type": "string",
                "description": "Server-generated task id. Poll it via record-info or receive it by callback.",
                "example": "0ba21f5f-2780-4a3a-bdcb-43b7dd401999"
              }
            }
          }
        }
      },
      "VocalRemovalGenerateRequest": {
        "type": "object",
        "required": [],
        "oneOf": [
          {
            "title": "Existing gateway audio",
            "required": [
              "taskId",
              "audioId"
            ]
          },
          {
            "title": "Public audio URL",
            "required": [
              "audioUrl"
            ]
          }
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "Gateway music task ID. Required with audioId."
          },
          "audioId": {
            "type": "string",
            "description": "Generated clip ID. Required with taskId and mutually exclusive with audioUrl."
          },
          "audioUrl": {
            "type": "string",
            "format": "uri",
            "description": "Public HTTP(S) audio URL, at most 20 MB. Mutually exclusive with taskId/audioId."
          },
          "type": {
            "type": "string",
            "enum": [
              "separate_vocal",
              "split_stem",
              "split_stem_advanced"
            ],
            "default": "separate_vocal"
          },
          "stemName": {
            "type": "string",
            "enum": [
              "Lead Vocal",
              "Drum Kit",
              "Kick",
              "Snare",
              "Risers",
              "Bass",
              "Backing Vocals",
              "Piano",
              "Electric Guitar",
              "Percussion",
              "String Section",
              "Synth",
              "Acoustic Guitar",
              "Sound Effects",
              "Synth Pad",
              "Synth Bass",
              "Guitar",
              "Brass Section",
              "Organ",
              "Electronic Drum Kit",
              "Lead Electric Guitar",
              "Synth Keys",
              "Rhythm Electric Guitar",
              "Electric Piano",
              "Upright Bass",
              "Keyboards",
              "Distorted Electric Guitar",
              "Synth Strings",
              "Synth Lead",
              "Woodwinds",
              "Rhythm Acoustic Guitar",
              "Flute",
              "Harp",
              "Tambourine",
              "Trumpet",
              "Arpeggiator",
              "Accordion",
              "Fiddle",
              "Pedal Steel Guitar",
              "Synth Voice",
              "Violin",
              "Digital Piano",
              "Synth Brass",
              "Mandolin",
              "Choir",
              "Banjo",
              "Bells",
              "Clarinet",
              "Tenor Saxophone",
              "Trombone",
              "Shaker",
              "French Horn",
              "Glockenspiel",
              "Electric Bass",
              "Cello",
              "Timpani",
              "Harmonica",
              "Marimba",
              "Vibraphone",
              "Lap Steel Guitar",
              "Saxophone",
              "Orchestra",
              "Horns",
              "Cymbals",
              "Hand Clap",
              "Oboe",
              "Celesta",
              "Congas",
              "Drone",
              "Alto Saxophone",
              "Double Bass",
              "Ukulele",
              "Harpsichord",
              "Baritone Saxophone",
              "Xylophone",
              "Tuba",
              "Bass Guitar",
              "Whistle",
              "Lead Guitar",
              "Rhodes",
              "808",
              "Bongos",
              "Bassoon",
              "Cowbell",
              "Viola",
              "Sitar",
              "Steel Drums",
              "Piccolo",
              "Theremin",
              "Bagpipes",
              "Hi-Hat",
              "Music Box",
              "Melodica",
              "Tabla",
              "Koto",
              "Djembe",
              "Taiko",
              "Didgeridoo"
            ],
            "description": "Required only for split_stem_advanced and forwarded verbatim to the captured stem fields."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1
          }
        }
      },
      "VocalRemovalCallbackEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg"
        ],
        "properties": {
          "code": {
            "type": "integer"
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "task_id": {
                "type": "string"
              },
              "vocal_removal_info": {
                "type": "object",
                "properties": {
                  "origin_url": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "instrumental_url": {
                    "type": "string"
                  },
                  "vocal_url": {
                    "type": "string"
                  },
                  "backing_vocals_url": {
                    "type": "string"
                  },
                  "drums_url": {
                    "type": "string"
                  },
                  "bass_url": {
                    "type": "string"
                  },
                  "guitar_url": {
                    "type": "string"
                  },
                  "keyboard_url": {
                    "type": "string"
                  },
                  "percussion_url": {
                    "type": "string"
                  },
                  "strings_url": {
                    "type": "string"
                  },
                  "synth_url": {
                    "type": "string"
                  },
                  "fx_url": {
                    "type": "string"
                  },
                  "brass_url": {
                    "type": "string"
                  },
                  "woodwinds_url": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "VocalRemovalRecordInfoEnvelope": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SubmitEnvelope"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "object",
                "properties": {
                  "taskId": {
                    "type": "string"
                  },
                  "musicId": {
                    "type": "string"
                  },
                  "musicIndex": {
                    "type": "integer"
                  },
                  "callbackUrl": {
                    "type": "string"
                  },
                  "completeTime": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "response": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "originUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "originData": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "duration": {
                              "type": [
                                "number",
                                "null"
                              ]
                            },
                            "audio_url": {
                              "type": "string"
                            },
                            "stem_type_group_name": {
                              "type": "string"
                            },
                            "id": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "instrumentalUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "vocalUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "backingVocalsUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "drumsUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "bassUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "guitarUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "keyboardUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "percussionUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "stringsUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "synthUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "fxUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "brassUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "woodwindsUrl": {
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    }
                  },
                  "successFlag": {
                    "type": "string",
                    "enum": [
                      "PENDING",
                      "SUCCESS",
                      "CREATE_TASK_FAILED",
                      "GENERATE_AUDIO_FAILED",
                      "CALLBACK_EXCEPTION"
                    ]
                  },
                  "createTime": {
                    "type": "string"
                  },
                  "errorCode": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "errorMessage": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              }
            }
          }
        ]
      },
      "MidiGenerateRequest": {
        "type": "object",
        "required": [
          "taskId"
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "Completed vocal-removal task ID."
          },
          "audioId": {
            "type": "string",
            "description": "Optional separated track ID from originData. Omit to process every separated track."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1
          }
        }
      },
      "MidiCallbackEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer"
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "taskId": {
                "type": "string"
              },
              "midiData": {
                "$ref": "#/components/schemas/MidiData"
              }
            }
          }
        }
      },
      "MidiNote": {
        "type": "object",
        "required": [
          "pitch",
          "start",
          "end",
          "velocity"
        ],
        "properties": {
          "pitch": {
            "type": "integer",
            "minimum": 0,
            "maximum": 127
          },
          "start": {
            "type": "number"
          },
          "end": {
            "type": "number"
          },
          "velocity": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          }
        }
      },
      "MidiInstrument": {
        "type": "object",
        "required": [
          "name",
          "notes"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "notes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MidiNote"
            }
          }
        }
      },
      "MidiData": {
        "type": "object",
        "required": [
          "state",
          "instruments"
        ],
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "complete"
            ]
          },
          "instruments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MidiInstrument"
            }
          }
        }
      },
      "MidiRecordInfoEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer"
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "taskId": {
                "type": "string"
              },
              "recordTaskId": {
                "type": "integer"
              },
              "audioId": {
                "type": "string"
              },
              "callbackUrl": {
                "type": "string"
              },
              "completeTime": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "midiData": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/MidiData"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "successFlag": {
                "type": "integer",
                "enum": [
                  0,
                  1,
                  2,
                  3
                ]
              },
              "createTime": {
                "type": "integer"
              },
              "errorCode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "errorMessage": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "CoverArtGenerateRequest": {
        "type": "object",
        "required": [
          "taskId"
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "Completed owned music-generation task ID."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "minLength": 1
          }
        }
      },
      "CoverArtCallbackEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "enum": [
              200,
              501
            ]
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "taskId",
              "images"
            ],
            "properties": {
              "taskId": {
                "type": "string"
              },
              "images": {
                "oneOf": [
                  {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uri"
                    }
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        }
      },
      "CoverArtRecordInfoEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer"
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "taskId",
              "parentTaskId",
              "callbackUrl",
              "completeTime",
              "response",
              "successFlag",
              "createTime",
              "errorCode",
              "errorMessage"
            ],
            "properties": {
              "taskId": {
                "type": "string"
              },
              "parentTaskId": {
                "type": "string"
              },
              "callbackUrl": {
                "type": "string"
              },
              "completeTime": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "response": {
                "type": "object",
                "properties": {
                  "images": {
                    "oneOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uri"
                        }
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                }
              },
              "successFlag": {
                "type": "integer",
                "enum": [
                  0,
                  1,
                  2,
                  3
                ]
              },
              "createTime": {
                "type": "string",
                "format": "date-time"
              },
              "errorCode": {
                "type": [
                  "integer",
                  "null"
                ],
                "enum": [
                  200,
                  500,
                  null
                ]
              },
              "errorMessage": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "MashupGenerateRequest": {
        "type": "object",
        "required": [
          "uploadUrlList",
          "customMode",
          "model"
        ],
        "properties": {
          "uploadUrlList": {
            "type": "array",
            "description": "Array containing exactly 2 audio file URLs to be mashed up together. Both URLs must be valid and accessible.",
            "items": {
              "type": "string",
              "format": "uri"
            },
            "minItems": 2,
            "maxItems": 2,
            "example": [
              "https://storage.example.com/audio1.mp3",
              "https://storage.example.com/audio2.mp3"
            ]
          },
          "customMode": {
            "type": "boolean",
            "description": "Custom mode is required in this version. `true` requires style and title, plus prompt for vocal Mashup. `false` is part of the public compatibility surface but is temporarily rejected until captured.",
            "example": true
          },
          "prompt": {
            "type": "string",
            "description": "A description of the desired audio content.  \n- In Custom Mode (`customMode: true`): Required if `instrumental` is `false`. The prompt will be strictly used as the lyrics and sung in the generated track. Character limits by model:  \n  - **V4**: Maximum 3000 characters  \n  - **V4_5, V4_5PLUS, V4_5ALL, V5 & V5_5**: Maximum 5000 characters  \n  Example: \"A calm and relaxing piano track with soft melodies\"  \n- In Non-custom Mode (`customMode: false`): Always required. The prompt serves as the core idea, and lyrics will be automatically generated based on it (not strictly matching the input). Maximum 500 characters.  \n  Example: \"A short relaxing piano tune\"",
            "example": "A calm and relaxing piano track with soft melodies"
          },
          "style": {
            "type": "string",
            "description": "The music style or genre for the audio.  \n- Required in Custom Mode (`customMode: true`). Examples: \"Jazz\", \"Classical\", \"Electronic\". Character limits by model:  \n  - **V4**: Maximum 200 characters  \n  - **V4_5, V4_5PLUS, V4_5ALL, V5 & V5_5**: Maximum 1000 characters  \n  Example: \"Classical\"  \n- In Non-custom Mode (`customMode: false`): Leave empty.",
            "example": "Classical"
          },
          "title": {
            "type": "string",
            "description": "The title of the generated music track.  \n- Required in Custom Mode (`customMode: true`). Character limits by model:  \n  - **V4 & V4_5ALL**: Maximum 80 characters  \n  - **V4_5, V4_5PLUS, V5 & V5_5**: Maximum 100 characters  \n  Example: \"Peaceful Piano Meditation\"  \n- In Non-custom Mode (`customMode: false`): Leave empty.",
            "maxLength": 100,
            "example": "Peaceful Piano Meditation"
          },
          "instrumental": {
            "type": "boolean",
            "description": "Determines if the audio should be instrumental (no lyrics).  \n- In Custom Mode (`customMode: true`):  \n  - If `true`: Only `style` and `title` are required.  \n  - If `false`: `style`, `title`, and `prompt` are required (with `prompt` used as the exact lyrics).  \n- In Non-custom Mode (`customMode: false`): No impact on required fields (`prompt` only). Lyrics are auto-generated if `instrumental` is `false`.",
            "example": true
          },
          "model": {
            "type": "string",
            "description": "Only V5 is currently accepted for Mashup because it is the captured model variant.",
            "enum": [
              "V5"
            ],
            "example": "V5"
          },
          "vocalGender": {
            "type": "string",
            "description": "Preferred vocal gender. Accepted but currently ignored until an upstream mapping is captured.",
            "enum": [
              "m",
              "f"
            ],
            "example": "m"
          },
          "styleWeight": {
            "type": "number",
            "description": "Weight of the provided style guidance. Accepted but currently ignored until an upstream mapping is captured.",
            "minimum": 0,
            "maximum": 1,
            "multipleOf": 0.01,
            "example": 0.65
          },
          "weirdnessConstraint": {
            "type": "number",
            "description": "Creativity constraint. Accepted but currently ignored until an upstream mapping is captured.",
            "minimum": 0,
            "maximum": 1,
            "multipleOf": 0.01,
            "example": 0.65
          },
          "audioWeight": {
            "type": "number",
            "description": "Input-audio weight. Accepted but currently ignored until an upstream mapping is captured.",
            "minimum": 0,
            "maximum": 1,
            "multipleOf": 0.01,
            "example": 0.65
          },
          "duration": {
            "type": "integer",
            "description": "Optional duration in seconds. Accepted but currently ignored until an upstream mapping is captured.",
            "minimum": 10,
            "maximum": 360,
            "example": 20
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "description": "The URL to receive task completion notifications when mashup generation is complete.\n- For detailed callback format and implementation guide, see [Music Generation Callbacks](https://docs.sunoapi.org/suno-api/generate-music-callbacks)\n- Alternatively, you can use the get music generation details endpoint to poll task status",
            "example": "https://api.example.com/callback"
          }
        }
      },
      "WavGenerateRequest": {
        "type": "object",
        "required": [
          "taskId",
          "audioId"
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "The music task that created the source track."
          },
          "audioId": {
            "type": "string",
            "description": "The specific track within the task to convert to WAV."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL receiving the single WAV completion notification."
          }
        }
      },
      "WavCallbackEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "enum": [
              200,
              500
            ]
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "audioWavUrl",
                  "task_id"
                ],
                "properties": {
                  "audioWavUrl": {
                    "type": "string",
                    "description": "Signed WAV download URL."
                  },
                  "task_id": {
                    "type": "string",
                    "description": "The WAV conversion task id."
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "WavRecordInfoEnvelope": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "const": 200
          },
          "msg": {
            "type": "string",
            "const": "success"
          },
          "data": {
            "$ref": "#/components/schemas/WavRecordInfo"
          }
        }
      },
      "WavRecordInfo": {
        "type": "object",
        "properties": {
          "taskId": {
            "type": "string"
          },
          "musicId": {
            "type": "string",
            "description": "Source music track id that was converted."
          },
          "musicIndex": {
            "type": "integer",
            "description": "Position of the track within its task, 0 or 1."
          },
          "callbackUrl": {
            "type": "string"
          },
          "completeTime": {
            "type": [
              "string",
              "null"
            ],
            "description": "Completion timestamp; null while pending."
          },
          "response": {
            "type": "object",
            "properties": {
              "audioWavUrl": {
                "type": "string",
                "description": "Signed WAV download URL; empty until complete."
              }
            }
          },
          "successFlag": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUCCESS",
              "CREATE_TASK_FAILED",
              "GENERATE_WAV_FAILED"
            ]
          },
          "createTime": {
            "type": "string"
          },
          "errorCode": {
            "type": [
              "number",
              "null"
            ]
          },
          "errorMessage": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Mp4GenerateRequest": {
        "type": "object",
        "required": [
          "taskId",
          "audioId"
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "The music task that created the source track."
          },
          "audioId": {
            "type": "string",
            "description": "The specific track within the task to convert to video."
          },
          "author": {
            "type": "string",
            "maxLength": 50,
            "description": "Accepted for reference compatibility; not forwarded upstream."
          },
          "domainName": {
            "type": "string",
            "maxLength": 50,
            "description": "Accepted for reference compatibility; not forwarded upstream."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL receiving the single MP4 completion notification."
          }
        }
      },
      "Mp4CallbackEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "enum": [
              200,
              500
            ]
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "task_id",
                  "video_url"
                ],
                "properties": {
                  "task_id": {
                    "type": "string",
                    "description": "The MP4 render task id."
                  },
                  "video_url": {
                    "type": "string",
                    "description": "Signed MP4 download URL."
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "Mp4RecordInfoEnvelope": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "const": 200
          },
          "msg": {
            "type": "string",
            "const": "success"
          },
          "data": {
            "$ref": "#/components/schemas/Mp4RecordInfo"
          }
        }
      },
      "Mp4RecordInfo": {
        "type": "object",
        "properties": {
          "taskId": {
            "type": "string"
          },
          "musicId": {
            "type": "string",
            "description": "Source music track id that was converted."
          },
          "musicIndex": {
            "type": "integer",
            "description": "Position of the track within its task, 0 or 1."
          },
          "callbackUrl": {
            "type": "string"
          },
          "completeTime": {
            "type": [
              "string",
              "null"
            ],
            "description": "Completion timestamp; null while pending."
          },
          "response": {
            "type": "object",
            "properties": {
              "videoUrl": {
                "type": "string",
                "description": "Signed MP4 download URL; empty until complete."
              }
            }
          },
          "successFlag": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUCCESS",
              "CREATE_TASK_FAILED",
              "GENERATE_MP4_FAILED"
            ]
          },
          "createTime": {
            "type": "string"
          },
          "errorCode": {
            "type": [
              "number",
              "null"
            ]
          },
          "errorMessage": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "LyricsCallbackEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "enum": [
              200,
              400,
              451,
              500
            ]
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "callbackType",
              "taskId",
              "data"
            ],
            "properties": {
              "callbackType": {
                "type": "string",
                "enum": [
                  "complete",
                  "error"
                ]
              },
              "taskId": {
                "type": "string"
              },
              "data": {
                "oneOf": [
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/LyricsVariant"
                    }
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        }
      },
      "MusicCallbackEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "enum": [
              200,
              400,
              451,
              500
            ]
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "callbackType",
              "task_id",
              "data"
            ],
            "properties": {
              "callbackType": {
                "type": "string",
                "enum": [
                  "text",
                  "first",
                  "complete",
                  "error"
                ]
              },
              "task_id": {
                "type": "string"
              },
              "data": {
                "oneOf": [
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/MusicCallbackTrack"
                    }
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        }
      },
      "MusicCallbackTrack": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "audio_url": {
            "type": "string"
          },
          "source_audio_url": {
            "type": "string"
          },
          "stream_audio_url": {
            "type": "string"
          },
          "source_stream_audio_url": {
            "type": "string"
          },
          "image_url": {
            "type": "string"
          },
          "source_image_url": {
            "type": "string"
          },
          "prompt": {
            "type": "string"
          },
          "model_name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "tags": {
            "type": "string"
          },
          "createTime": {
            "type": "string"
          },
          "duration": {
            "type": "number"
          }
        }
      },
      "RecordInfoEnvelope": {
        "type": "object",
        "description": "Standard `{code, msg, data}` envelope; `data` is the task state.",
        "properties": {
          "code": {
            "type": "integer",
            "const": 200
          },
          "msg": {
            "type": "string",
            "const": "success"
          },
          "data": {
            "$ref": "#/components/schemas/RecordInfo"
          }
        }
      },
      "RecordInfo": {
        "type": "object",
        "description": "The task state returned by record-info polling and the current lyrics terminal callback.",
        "properties": {
          "taskId": {
            "type": "string",
            "description": "The task id."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "TEXT_SUCCESS",
              "FIRST_SUCCESS",
              "SUCCESS",
              "GENERATE_AUDIO_FAILED",
              "GENERATE_LYRICS_FAILED",
              "SENSITIVE_WORD_ERROR",
              "CREATE_TASK_FAILED"
            ],
            "description": "Music: PENDING → TEXT_SUCCESS → FIRST_SUCCESS → SUCCESS | GENERATE_AUDIO_FAILED | CREATE_TASK_FAILED | SENSITIVE_WORD_ERROR. Lyrics: PENDING → SUCCESS | GENERATE_LYRICS_FAILED | SENSITIVE_WORD_ERROR | CREATE_TASK_FAILED."
          },
          "type": {
            "type": "string",
            "enum": [
              "GENERATE",
              "EXTEND",
              "COVER",
              "LYRICS"
            ],
            "description": "The kind of work this task performs."
          },
          "operationType": {
            "type": "string",
            "enum": [
              "generate",
              "extend",
              "cover",
              "lyrics"
            ],
            "description": "Lowercase operation name matching the task type."
          },
          "parentMusicId": {
            "type": "string",
            "description": "Source clip id for extension tasks; an empty string for normal generation."
          },
          "param": {
            "type": "string",
            "description": "The submitted input, rendered as a camelCase JSON string."
          },
          "response": {
            "type": "object",
            "description": "The result. Music tasks carry `sunoData[]`; lyrics tasks carry `data[]`. Arrays are empty until a result exists.",
            "properties": {
              "taskId": {
                "type": "string"
              },
              "sunoData": {
                "type": "array",
                "description": "Tracks. Empty until the status is SUCCESS.",
                "items": {
                  "$ref": "#/components/schemas/SunoTrack"
                }
              },
              "data": {
                "type": "array",
                "description": "Generated lyrics variants. This integration currently returns one variant.",
                "items": {
                  "$ref": "#/components/schemas/LyricsVariant"
                }
              }
            }
          },
          "errorCode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set only on failed tasks; otherwise null."
          },
          "errorMessage": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set only on failed tasks; otherwise null."
          }
        }
      },
      "SunoTrack": {
        "type": "object",
        "description": "One generated track.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Clip id—use as `audioId` for extension."
          },
          "title": {
            "type": "string",
            "description": "Track title; may be empty for simple generations."
          },
          "audioUrl": {
            "type": "string",
            "description": "Audio URL served by this gateway: `GET /api/v1/media/{clipId}` on `server.public_base_url` (a site-relative path when that is unset). Suno no longer publishes clip audio directly, so the gateway fetches and decrypts it on request, then transcodes to MP3 (`audio/mpeg`, 192 kbps) without storing anything. Append `?format=m4a` for Suno's own Opus-in-MP4 rendition, which is one lossy generation better. Empty until the clip is playable."
          },
          "streamAudioUrl": {
            "type": "string",
            "description": "Same gateway media URL as `audioUrl`; kept for compatibility with callers that use a separate streaming field."
          },
          "imageUrl": {
            "type": "string",
            "description": "Cover image URL."
          },
          "prompt": {
            "type": "string",
            "description": "Lyrics or prompt associated with the rendered track."
          },
          "modelName": {
            "type": "string",
            "description": "Upstream model that rendered the track, e.g. `V5`."
          },
          "tags": {
            "type": "string",
            "description": "Style tags associated with the rendered track."
          },
          "createTime": {
            "type": "string",
            "description": "Upstream clip creation time."
          },
          "duration": {
            "type": "number",
            "description": "Audio duration in seconds when upstream reports it."
          }
        }
      },
      "LyricsVariant": {
        "type": "object",
        "required": [
          "text",
          "title",
          "status",
          "errorMessage"
        ],
        "properties": {
          "text": {
            "type": "string",
            "description": "Generated lyrics content."
          },
          "title": {
            "type": "string",
            "description": "Generated title; empty when upstream does not provide one."
          },
          "status": {
            "type": "string",
            "enum": [
              "complete",
              "failed"
            ]
          },
          "errorMessage": {
            "type": "string",
            "description": "Failure detail; empty for a complete variant."
          }
        }
      },
      "TimestampedLyricsRequest": {
        "type": "object",
        "required": [
          "taskId",
          "audioId"
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "Gateway task that created the requested clip."
          },
          "audioId": {
            "type": "string",
            "description": "Generated clip whose word timings should be returned."
          }
        }
      },
      "TimestampedWord": {
        "type": "object",
        "required": [
          "word",
          "success",
          "startS",
          "endS",
          "palign"
        ],
        "properties": {
          "word": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          },
          "startS": {
            "type": "number",
            "description": "Word start time in seconds."
          },
          "endS": {
            "type": "number",
            "description": "Word end time in seconds."
          },
          "palign": {
            "type": "number",
            "description": "Upstream alignment confidence parameter."
          }
        }
      },
      "TimestampedLyricsEnvelope": {
        "type": "object",
        "required": [
          "code",
          "msg",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "const": 200
          },
          "msg": {
            "type": "string",
            "const": "success"
          },
          "data": {
            "type": "object",
            "required": [
              "alignedWords",
              "waveformData",
              "hootCer",
              "isStreamed"
            ],
            "properties": {
              "alignedWords": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TimestampedWord"
                }
              },
              "waveformData": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "description": "Currently an empty array: captured v3 returns multi-resolution waveform aggregates, not this public flat representation."
              },
              "hootCer": {
                "type": "number",
                "description": "Currently 0 because captured v3 does not return a public-compatible alignment error score."
              },
              "isStreamed": {
                "type": "boolean",
                "description": "Currently false because captured v3 does not return this field."
              }
            }
          }
        }
      },
      "ModelsEnvelope": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "const": 200
          },
          "msg": {
            "type": "string",
            "const": "success"
          },
          "data": {
            "type": "object",
            "properties": {
              "models": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Model"
                }
              }
            }
          }
        }
      },
      "Model": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The value to pass as `model`. Standard models use public aliases; custom models retain their raw key.",
            "example": "V5"
          },
          "label": {
            "type": "string",
            "description": "Human-readable model name.",
            "example": "v5"
          },
          "accountCount": {
            "type": "integer",
            "description": "Number of usable accounts backing this model.",
            "example": 1
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "description": "Standard `{code, msg}` envelope; `code` mirrors the HTTP status and `data` is omitted.",
        "properties": {
          "code": {
            "type": "integer"
          },
          "msg": {
            "type": "string"
          }
        }
      },
      "GeneratePersonaRequest": {
        "type": "object",
        "required": [
          "taskId",
          "audioId",
          "name",
          "description"
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "Original music task that owns the source clip."
          },
          "audioId": {
            "type": "string",
            "description": "Source clip the persona is derived from."
          },
          "name": {
            "type": "string",
            "description": "Persona name."
          },
          "description": {
            "type": "string",
            "description": "Persona description."
          },
          "vocalStart": {
            "type": "number",
            "format": "double",
            "description": "Vocal sample start in seconds. Defaults to 0.0."
          },
          "vocalEnd": {
            "type": "number",
            "format": "double",
            "description": "Vocal sample end in seconds. Defaults to 30.0."
          },
          "style": {
            "type": "string",
            "description": "Style text forwarded as user_input_styles."
          }
        }
      },
      "PersonaEnvelope": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "example": 200
          },
          "msg": {
            "type": "string",
            "example": "success"
          },
          "data": {
            "type": "object",
            "properties": {
              "personaId": {
                "type": "string",
                "description": "Created persona ID."
              },
              "name": {
                "type": "string",
                "description": "Persona name."
              }
            }
          }
        }
      },
      "ReplaceSectionRequest": {
        "type": "object",
        "required": [
          "prompt",
          "tags",
          "title",
          "infillStartS",
          "infillEndS",
          "fullLyrics"
        ],
        "properties": {
          "taskId": {
            "type": "string",
            "description": "Mode 1: original task that owns the source clip."
          },
          "audioId": {
            "type": "string",
            "description": "Mode 1: source clip to infill."
          },
          "uploadUrl": {
            "type": "string",
            "format": "uri",
            "description": "Mode 2: publicly reachable HTTP(S) audio URL."
          },
          "model": {
            "type": "string",
            "minLength": 1,
            "description": "Mode 2: generation model key."
          },
          "prompt": {
            "type": "string",
            "description": "New lyrics for the replaced section (exact custom lyrics)."
          },
          "tags": {
            "type": "string",
            "description": "Comma-separated style tags."
          },
          "title": {
            "type": "string",
            "description": "Track title."
          },
          "negativeTags": {
            "type": "string",
            "description": "Styles or traits to exclude."
          },
          "infillStartS": {
            "type": "number",
            "format": "double",
            "description": "Replace-from timestamp in seconds. Window must be at least 10 seconds."
          },
          "infillEndS": {
            "type": "number",
            "format": "double",
            "description": "Replace-to timestamp in seconds."
          },
          "fullLyrics": {
            "type": "string",
            "description": "Current full lyrics used to derive the out-of-window context."
          },
          "callBackUrl": {
            "type": "string",
            "format": "uri",
            "description": "Optional completion callback; poll via GET /api/v1/generate/record-info instead."
          }
        }
      },
      "ImageGenerateRequest": {
        "type": "object",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "maxLength": 32000,
            "description": "What to draw. The whole request."
          },
          "model": {
            "type": "string",
            "description": "Accepted for client compatibility; ignored."
          },
          "callBackUrl": {
            "type": "string",
            "description": "Receives one completion notification."
          }
        }
      },
      "ImageResponse": {
        "type": "object",
        "properties": {
          "taskId": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string",
            "description": "Absolute URL of the generated image when server.public_base_url is set, otherwise a path. Valid for `chatgpt.image_retention` (default 7 days); 404 afterwards."
          },
          "mimeType": {
            "type": "string",
            "example": "image/png"
          },
          "sizeBytes": {
            "type": "integer"
          }
        }
      },
      "ImageRecordInfo": {
        "type": "object",
        "properties": {
          "taskId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUCCESS",
              "CREATE_TASK_FAILED",
              "GENERATE_IMAGE_FAILED"
            ]
          },
          "param": {
            "type": "string",
            "description": "The persisted request payload, as JSON text."
          },
          "response": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ImageResponse"
              },
              {
                "type": "null"
              }
            ],
            "description": "Present only on SUCCESS."
          },
          "errorCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "errorMessage": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ImageRecordInfoEnvelope": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "const": 200
          },
          "msg": {
            "type": "string",
            "const": "success"
          },
          "data": {
            "$ref": "#/components/schemas/ImageRecordInfo"
          }
        }
      },
      "ImageCallbackEnvelope": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer"
          },
          "msg": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "callbackType": {
                "type": "string",
                "enum": [
                  "complete",
                  "error"
                ]
              },
              "taskId": {
                "type": "string"
              },
              "info": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ImageResponse"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        }
      },
      "OpenAIImageGenerationRequest": {
        "type": "object",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "maxLength": 32000
          },
          "model": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "n": {
            "type": "integer",
            "minimum": 1,
            "maximum": 4,
            "default": 1,
            "description": "Each image is one durable job and occupies one account slot."
          },
          "response_format": {
            "type": "string",
            "enum": [
              "b64_json",
              "url"
            ],
            "default": "b64_json"
          },
          "stream": {
            "type": "boolean",
            "description": "Rejected with 400: streaming is not supported."
          },
          "size": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "quality": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "background": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "output_format": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "output_compression": {
            "type": "integer",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "moderation": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "partial_images": {
            "type": "integer",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "style": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          },
          "user": {
            "type": "string",
            "description": "Accepted for OpenAI SDK compatibility; ignored."
          }
        }
      },
      "OpenAIImage": {
        "type": "object",
        "properties": {
          "b64_json": {
            "type": "string",
            "description": "Base64 image bytes; present when response_format is b64_json."
          },
          "url": {
            "type": "string",
            "description": "Gateway-hosted image URL; present when response_format is url. Valid for `chatgpt.image_retention` (default 7 days); 404 afterwards."
          }
        }
      },
      "OpenAIImagesResponse": {
        "type": "object",
        "properties": {
          "created": {
            "type": "integer"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenAIImage"
            }
          },
          "output_format": {
            "type": "string",
            "enum": [
              "png",
              "webp",
              "jpeg"
            ]
          }
        }
      },
      "OpenAIErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "invalid_request_error",
                  "rate_limit_error",
                  "server_error"
                ]
              },
              "param": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      }
    }
  }
}
