アップロード後カバー API
インターフェースの説明
アップロード後カバーは、音声ファイルまたは音声 URL を送信し、そのソース音声を元に新しいカバーバージョンを生成します。
エンドポイント: POST /api/music/upload-cover
課金: 有料、現在は既定で 1 回 0.6 元。本エンドポイントは「アップロード後カバー」であり、画像カバーのアップロードではありません。実際の請求額は現在の管理画面の価格設定に従います。
Max Mode / Variety: 本エンドポイントは任意パラメータ max_mode と variety(0〜4)に対応しています。
max_mode を有効にするとこの 1 回は 2 倍の価格で課金され(0.6 → 1.2 元/回)、variety に追加課金は
ありません。両者の意味と書き方は新版 API 概要の「高度なパラメータ」の節をご覧ください。
待ち時間とタイムアウト(重要): 本エンドポイントは同期インターフェースで、レスポンスが返った時点で初めて注文が受理され生成に投入されます。実測では多くのリクエストが 1〜3 秒で返り、約 10% が 30 秒を超え、最長は約 230 秒です。クライアントのタイムアウトは 300 秒以上に設定してください。レスポンスが無いことは未生成を意味せず、タイムアウト直後の再試行は注文の重複と二重課金につながります。 接続が切れた場合は少し後に
GET /api/music/songsで確認できます。詳しくは新版 API 概要の「待ち時間とタイムアウト設定」をご覧ください。
音声が大きい場合は「アップロード」と「カバー」を 2 ステップに分けることをおすすめします
本エンドポイントは音声全体をリクエストボディに入れる必要があります。音声が大きいほどボディも大きくなり、ネットワークの揺らぎやタイムアウトで途中で切れると、 サーバーは
unexpected end of JSON input(HTTP 400、課金なし)を返します。音声が約 8MB を超える場合、ネットワークが不安定な場合、同じソース素材を使い回す場合は、2 ステップ方式に切り替えてください。
POST /api/music/upload-sourceで先にソース音声をアップロード — 無料、いつでも再試行可能 — してclip_idを取得します。POST /api/music/generate-from-sourceでそのclip_idを使ってカバーを開始 — 課金されるステップのリクエストボディは約 250 バイトだけです。詳しくはソース音声アップロード API、ソース clip からのカバー API、 および本ページ末尾の「大きいファイルとリクエストの切断」をご覧ください。
リクエストパラメータ
Headers
| パラメータ名 | 型 | 必須 | 説明 |
|---|---|---|---|
| Authorization | string | はい | Bearer YOUR_API_KEY |
| Content-Type | string | はい | application/json |
Body パラメータ
| パラメータ名 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| model | string | いいえ | suno-v6 | 対客モデル名:suno-v6、suno-v6-wild、suno-v6-mini |
| file_url | string | いいえ | - | ソース音声の URL |
| file_base64 | string | いいえ | - | Base64 の音声 |
| file_name | string | いいえ | - | ファイル名 |
| prompt | string | いいえ | - | 新しい歌詞またはアレンジの方向性 |
| style | string | いいえ | - | スタイルタグ |
| title | string | いいえ | - | タイトル |
| negativeTags | string | いいえ | - | 負のスタイル |
| instrumental | boolean | いいえ | false | インストゥルメンタルかどうか |
| waitAudio | boolean | いいえ | false | 音声の完成を待つかどうか |
| cover_start_s | number | いいえ | - | カバーする区間の開始秒 |
| cover_end_s | number | いいえ | - | カバーする区間の終了秒 |
| audio_weight | number | いいえ | - | 参考音声への依存度、範囲 0.0-1.0。参考音声を指定した場合のみ送信できます |
cover_start_s と cover_end_s の単位は秒で、小数も指定できます。開始時刻は終了時刻より小さく、かつソース音声の長さを超えてはいけません。両方のフィールドを省略すると音声全体が対象になります。audio_weight は Suno の metadata.control_sliders.audio_weight にマッピングされ、生成結果が参考音声にどれだけ寄るかを制御します。値は 0.0-1.0 で、リクエストに有効な file_url または file_base64 の参考音声がある場合のみ付けられます。0 は有効な値で、フィールドを省略すると「指定なし」となり Suno の既定動作になります。instrumental と waitAudio は必ず JSON の真偽値を渡し、文字列は渡さないでください。
アップロードのエンドポイントは既定で非同期に返します。レスポンスの clips[].status が pending のとき、audio_url が空なのは正常で、アップロードやカバーの失敗を意味しません。返ってきた実 song_id を保存し、楽曲照会エンドポイントで完了になるまでポーリングしてから音声アドレスを読んでください。
リクエスト例
curl -X POST https://www.suno-api.io/api/music/upload-cover \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"file_url": "https://example.com/source.mp3",
"file_name": "source.mp3",
"prompt": "新しい歌詞またはアレンジの方向性",
"style": "Mandopop, acoustic guitar",
"title": "カバーバージョン",
"negativeTags": "noise, low quality",
"audio_weight": 0.5,
"instrumental": false,
"waitAudio": false,
"cover_start_s": 0,
"cover_end_s": 60
}'
レスポンス結果
{
"code": 200,
"message": "success",
"data": {
"upload": {
"clip_id": "uploaded_clip_id",
"status": "complete"
},
"clips": [
{
"song_id": "new_clip_id",
"song_title": "カバーバージョン",
"status": "pending"
}
]
}
}
大きいファイルとリクエストの切断
推奨:アップロードとカバーを 2 ステップに分ける
一括型のインターフェース(本エンドポイント)はアップロードと生成を 1 ステップにまとめます。つまり大きな body がその唯一のステップに現れるため、途中で切れると生成されたかどうかも、課金されたかどうかも判断しづらくなります。
| ステップ 1 アップロード | ステップ 2 カバー | |
|---|---|---|
| エンドポイント | POST /api/music/upload-source |
POST /api/music/generate-from-source |
| 課金 | 無料(アップロードのみ、生成なし) | 1 回 0.6 元。Max Mode 有効時は 1 回 1.2 元 |
| リクエストボディ | 音声そのもの(base64 / multipart)、または file_url でリンクのみ |
約 250 バイト(sourceClipId を 1 つ渡すだけ) |
| 戻り値 | clip_id(ソース音声の clip ID) |
data.clips[].song_id(生成結果) |
| 失敗したら | そのまま再試行。課金なし・生成タスクも作られない | クライアントのタイムアウトを 300 秒以上に。タイムアウト時はまず /api/music/songs で確認し、すぐ再試行しない |
| ソース素材の再利用 | 同じ clip_id を続き生成 / 置換 / 分離にも使える |
毎回音声を再送する必要がある |
結論:音声が約 8MB 超、ネットワークが不安定、同じ素材を複数回使う → 2 ステップ方式。音声が小さくネットワークが安定 → 本エンドポイントのほうが手軽です。
400 unexpected end of JSON input とは
意味はサーバーが受け取った JSON が不完全ということです(パラメータの誤りでも、権限や残高の問題でもありません)。よくある原因を確率順に挙げます。
- 大きな body が転送中に切断された:接続層は「クライアントが送ると宣言した量」と「実際に届いた量」の両方を記録します。実測例では、クライアントの宣言が 14.17MB に対し実際の到達は 11.8〜12.4MB、3 回のリクエストはいずれも約 1.6〜1.7 秒で停止しました。不足バイト数が毎回異なることから、固定の上限ではなく転送の中断だと分かります(サーバーはリクエストボディのサイズを制限していません)。
Content-Lengthと実際に送信したバイト数が一致しない:Node.js で文字列の.length(UTF-16 の文字数)を長さとして使うと、中国語などのマルチバイト文字で誤ります。- body を Buffer ではなく文字列で書いたため、実際のバイト数が宣言と合わない。
いずれも課金の前に起きるので、費用は発生しません。
クライアント側のセルフチェック
-
Content-LengthはBuffer.byteLength(json, 'utf8')(またはBuffer.from(json).length)で求める。json.lengthは使わない。 - リクエストボディは Buffer として書き出す(文字列で書かない)。
- socket / リクエストのタイムアウトは 300 秒以上。
- 音声が約 8MB を超える場合:
file_urlに切り替える(ボディは数百バイト)、upload-sourceの multipart を使う、または 2 ステップ方式にする。 - multipart リクエストでは**
Content-Typeを手動で設定しない**(boundary はクライアントに任せる)。 - 「実際に送信したバイト数」を出力し、
Content-Lengthと比較する。 - 2 ステップ方式では、ステップ 1 が
clip_idを返しstatusが完了態になったのを確認してからステップ 2 を送る。
よくあるエラー一覧
| エラー | 意味 | 対応 |
|---|---|---|
unexpected end of JSON input |
リクエストボディが不完全(切断) | 上のセルフチェックを行う。または 2 ステップ方式に切り替える |
invalid character '-' in numeric literal |
multipart の body を JSON エンドポイントに送った | JSON エンドポイントで multipart を使わない。Content-Type を手動設定しない |
one of file_path, file_base64, file_url, or multipart file is required |
音声が付いていない | file_base64 / file_url / multipart の file を付ける |
model is required |
リクエストボディが空の正当な JSON(例:{}) |
少なくとも model を付ける |
Invalid request: Invalid request, ... |
ボディ解析失敗のラッパー | 後半の具体的な理由を見る(多くは上のいずれか) |
関連エンドポイント:ソース音声アップロード API(ステップ 1)、ソース clip からのカバー API(ステップ 2)。