# 生成音乐
> Flow Music 的主生成接口，异步任务
> 与 Suno 共用同一个端点，靠 `model` 字段区分
> 单次请求出 1 首
`POST /v1/music/generations`
## 认证
- `Authorization` (string / 必填) — 所有接口均使用 Bearer Token 进行认证。 获取 API Key：[访问控制台](https://api.oairoute.com/keys) 创建。 请求时在请求头中添加： ```http Authorization: Bearer YOUR_OAIRoute_KEY ```
## 请求参数
- `model` (string / 必填) — 固定填 `flowmusic`，大小写不敏感。 注意：同一个端点也承载 Suno，那边填 `suno`。两者靠这个字段分流。
- `sound_prompt` (string / 条件必填) — 音乐风格与音色描述提示词。例如「明快的流行乐，带钢琴前奏」。 `sound_prompt` 与 `lyrics` 至少传一个，不能同时为空。
- `lyrics` (string / 条件必填) — 歌词正文。可以先调「生成歌词」接口拿到再回填。 与 `sound_prompt` 至少传一个。
- `title` (string / 可选) — 生成音乐的标题。
- `bpm` (string / 可选) — 每分钟节拍数。**类型是字符串**，例如 `"120"`，数值须不小于 1。
- `length` (integer / 可选) — 生成时长，取值 1 到 240，单位秒。
- `seed` (string / 可选) — 复现用的随机种子，任意字符串。相同请求与相同 seed 结果相似，但不保证完全一致。
## 提交响应
- `code` (integer) — 状态码，成功为 200。
- `data[].status` (string) — 任务状态，提交成功时为 `submitted`。
- `data[].task_id` (string) — 任务唯一标识，用于后续查询。
## 任务查询响应
用 `GET /v1/music/tasks/{task_id}` 查询。
- `data.id` (string) — 任务 ID。
- `data.status` (string) — 已完成时为 `completed`。
- `data.progress` (integer) — 进度百分比。
- `data.created` (integer) — 创建时间，Unix 秒。
- `data.completed` (integer) — 完成时间，Unix 秒。
- `data.actual_time` (integer) — 实际耗时，单位秒。
- `data.cost` (number) — 费用，美元。
- `data.credits_cost` (number) — 积分消耗。
- `data.result.music` (array) — 生成的音乐列表。
## music[] 元素字段
- `clip_id` (string) — 音频片段 UUID。
- `title` (string) — 曲目标题。
- `duration_seconds` (string) — 时长，**字符串形式的浮点秒数**，例如 `"184.2"`。
- `create_time` (string) — ISO 8601 时间戳。
- `lyrics` (string) — 该曲使用的歌词文本。
- `lyrics_id` (string) — 歌词 UUID。
- `lyrics_timing_markers` (array) — 时间标记，二元组数组，形如 `[[10,12],[212,36]]`，元素为整数对。
- `audio_url` (string) — 音频地址，`.m4a` 格式。
- `wav_url` (string) — WAV 格式地址。
- `image_url` (string) — 封面图地址，`.jpg` 格式。
## 与 Suno 的差异
| 项目 | Flow Music | Suno |
|---|---|---|
| `model` 取值 | `flowmusic` | `suno` |
| 提示词字段 | `sound_prompt` | `prompt` |
| 时长字段 | `length`（秒，1–240） | `duration`（秒，10–360） |
| 节拍控制 | `bpm` | 无 |
| 结果时长字段 | `duration_seconds`（字符串） | `duration`（数字） |
| 歌词时间轴 | `lyrics_timing_markers` | 无 |
| 追加格式 | 额外给 `wav_url` | 无 |
## 错误
| HTTP | type | code | message |
|---|---|---|---|
| 400 | invalid_request | invalid_request | sound_prompt 与 lyrics 不能同时为空 |
| 429 | rate_limit_error | rate_limit_error | 当前分组容量饱和，请稍后重试 |
> **Note:** 
> `duration_seconds` 是字符串不是数字。直接做算术会得到字符串拼接的结果，需要先 `float()` 或 `Number()` 转换。
更多状态码与重试建议见[错误码与限流](../../../support/errors.html)，常见报错的排查步骤见[常见问题](../../../support/faq.html)。
## 使用示例
提交一个任务并拿到 `task_id`：
> **Note:** 
> 提交成功只表示任务已受理。真正的产物要拿返回的 `task_id` 去任务查询接口轮询，`status` 变成 `completed` 之后才有结果。
**生成音乐{Generate music}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/music/generations' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "flowmusic",
    "sound_prompt": "明快的流行乐，带钢琴前奏",
    "length": 120,
    "bpm": "120"
  }'
```
**生成音乐{Generate music}::Python**
```
import requests
res = requests.post(
    "https://api.oairoute.com/v1/music/generations",
    headers={
        "Authorization": "Bearer YOUR_OAIRoute_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "flowmusic",
        "sound_prompt": "明快的流行乐，带钢琴前奏",
        "length": 120,
        "bpm": "120",
    },
)
task_id = res.json()["data"][0]["task_id"]
print("任务号", task_id)
```
**生成音乐{Generate music}::JavaScript**
```
const url = "https://api.oairoute.com/v1/music/generations";
const options = {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "flowmusic",
    "sound_prompt": "明快的流行乐，带钢琴前奏",
    "length": 120,
    "bpm": "120"
  }),
};
fetch(url, options)
  .then((res) => res.json())
  .then((json) => console.log(json))
  .catch((err) => console.error(err));
```
**200 生成音乐{Generate music}**
```
{
  "code": 200,
  "data": [
    { "status": "submitted", "task_id": "task_01K8AYYM6R03TGZ3Q2P0TZVNPX" }
  ]
}
```
**带歌词{With lyrics}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/music/generations' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "flowmusic",
  "sound_prompt": "温柔的民谣，木吉他",
  "lyrics": "清晨的窗边\n光线慢慢铺开",
  "title": "窗边",
  "length": 180,
  "bpm": "88"
}'
```
**带歌词{With lyrics}::Python**
```
import requests
url = "https://api.oairoute.com/v1/music/generations"
headers = {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
}
payload = {
      "model": "flowmusic",
      "sound_prompt": "温柔的民谣，木吉他",
      "lyrics": "清晨的窗边\n光线慢慢铺开",
      "title": "窗边",
      "length": 180,
      "bpm": "88"
    }
res = requests.post(url, headers=headers, json=payload)
print(res.json())
```
**带歌词{With lyrics}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/v1/music/generations", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "flowmusic",
    "sound_prompt": "温柔的民谣，木吉他",
    "lyrics": "清晨的窗边\n光线慢慢铺开",
    "title": "窗边",
    "length": 180,
    "bpm": "88"
  }),
});
console.log(await res.json());
```
**200 带歌词{With lyrics}**
```
{
  "code": 200,
  "data": [
    { "status": "submitted", "task_id": "task_01K8AYYM6R03TGZ3Q2P0TZVNPX" }
  ]
}
```
