> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soundpiece.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Remix a song

> Make new versions of a song with vocals, with new lyrics and a new style

`create.remix_song` takes a song that has vocals and makes new versions of it: the vocal line of the original, sung with your new lyrics, in the style your prompt describes. Use it to personalise a song (a name, a brand, an occasion), to re-style a track in another genre, or to try out new words over a melody you already have.

The source must contain vocals. To remix music without vocals, use [`create.remix_instrumental`](/guides/create/remix_instrumental).

***

## The request

| Field | Required | What it is |
| - | - | - |
| `source` | yes | The song to remix: `{"url": "https://..."}`, a public link to a WAV, MP3 or FLAC file with vocals. |
| `lyrics` | yes | The new words to sing, up to 3,000 characters, with section markers such as `[Verse]` and `[Chorus]`. |
| `prompt` | yes | A description of the new style, up to 1,024 characters, e.g. `"acoustic folk, warm, female vocal"`. |
| `n_variations` | no | How many different versions to make, from 1 to 3. Defaults to 1. |
| `loudness` | no | Normalise every version to a target loudness, at no extra cost. Leave it out to get them as produced. See [Loudness](/loudness). |
| `idempotency_key` | yes | A UUID that identifies this job. The [reference client](/client) fills it in for you. |
| `callback_url` | no | An HTTPS address to receive a [webhook](/webhooks) when the work is finished. |

Every field, with its exact rules: [submit](/api-reference/create/remix_song/submit) and [poll](/api-reference/create/remix_song/poll) in the API Reference.

***

## Example

This remixes a song into two acoustic versions with new lyrics and saves them. It uses the [reference client](/client); save `soundpiece.py` or `soundpiece.mjs` next to it first.

```python remix.py theme={null}
import soundpiece

remix = soundpiece.run("create.remix_song", {
    "source": {"url": "https://example.com/audio/song.mp3"},
    "lyrics": "[Verse]\nMorning light on the harbour wall\n\n[Chorus]\nHappy birthday, Sam, this song is for you",
    "prompt": "acoustic folk, warm, female vocal",
    "n_variations": 2,
})

for number, output in enumerate(remix["outputs"], start=1):
    soundpiece.download(output["url"], f"remix-{number}.flac")
    print(f"Saved remix-{number}.flac")
```

```javascript remix.mjs theme={null}
import { run, download } from "./soundpiece.mjs";

const remix = await run("create.remix_song", {
  source: { url: "https://example.com/audio/song.mp3" },
  lyrics: "[Verse]\nMorning light on the harbour wall\n\n[Chorus]\nHappy birthday, Sam, this song is for you",
  prompt: "acoustic folk, warm, female vocal",
  n_variations: 2,
});

for (const [index, output] of remix.outputs.entries()) {
  await download(output.url, `remix-${index + 1}.flac`);
  console.log(`Saved remix-${index + 1}.flac`);
}
```

```bash cURL theme={null}
#!/usr/bin/env bash
# Submit, wait and download by hand. Needs curl, jq and uuidgen.
set -euo pipefail
API=https://api.soundpiece.co/v1
AUTH="Authorization: Bearer $SOUNDPIECE_API_KEY"

# 1. Submit. Sending this exact body again (same idempotency_key) is safe.
body=$(jq -n --arg key "$(uuidgen)" '{
  idempotency_key: $key,
  source: { url: "https://example.com/audio/song.mp3" },
  lyrics: "[Verse]\nMorning light on the harbour wall\n\n[Chorus]\nHappy birthday, Sam, this song is for you",
  prompt: "acoustic folk, warm, female vocal",
  n_variations: 2
}')
response=$(curl --silent --show-error --max-time 30 --request PUT "$API/create.remix_song" \
  --header "$AUTH" --header "Content-Type: application/json" --data "$body")
result=$(jq -e .remixed_song <<<"$response") || { echo "$response"; exit 1; }
id=$(jq -r .id <<<"$result")

# 2. Wait. Each call returns as soon as the work is finished, or after 20 seconds.
while [ "$(jq -r .status <<<"$result")" = processing ]; do
  response=$(curl --silent --show-error --max-time 30 "$API/create.remix_song?id=$id&wait=true" \
    --header "$AUTH")
  result=$(jq -e .remixed_song <<<"$response") || { echo "$response"; exit 1; }
done

# 3. Download each version, or show what went wrong.
if [ "$(jq -r .status <<<"$result")" = failed ]; then
  jq .error <<<"$result"
  exit 1
fi
number=0
for url in $(jq -r '.outputs[].url' <<<"$result"); do
  number=$((number + 1))
  curl --silent --show-error --fail --output "remix-$number.flac" "$url"
  echo "Saved remix-$number.flac"
done
```

***

## The result

`run` returns the finished `remixed_song` object, with one entry in `outputs` per variation:

```json theme={null}
{
  "id": "op_01ks2qmt3wk17f3g9h0j2m5n8p",
  "status": "ready",
  "created_at": "2026-10-10T09:15:02Z",
  "idempotency_key": "b8c9d0e1-f2a3-4b4c-9d5e-6f7a8b9c0d1e",
  "lyrics": "[Verse]\nMorning light on the harbour wall\n\n[Chorus]\nHappy birthday, Sam, this song is for you",
  "prompt": "acoustic folk, warm, female vocal",
  "n_variations": 2,
  "outputs": [
    { "url": "https://cdn.soundpiece.co/...signed...", "expires_at": "2026-10-10T09:31:40Z", "duration": 176.2 },
    { "url": "https://cdn.soundpiece.co/...signed...", "expires_at": "2026-10-10T09:31:40Z", "duration": 181.5 }
  ],
  "error": null
}
```

| Field | What it means |
| - | - |
| `lyrics`, `prompt`, `n_variations` | What you asked for. The source URL is never echoed. |
| `loudness` | Present only if you asked for normalisation (not in this example). |
| `outputs[].url` | A signed link to one version, as a FLAC file (44.1 kHz). It needs no API key. |
| `outputs[].expires_at` | When the link stops working. Poll the operation again for a fresh one. |
| `outputs[].duration` | The version's length in seconds. |
| `outputs[].loudness` | Present only if you asked for normalisation: `lufs`, `true_peak_dbtp` and `compressed`, measured on that version. |

***

## Choosing parameters

* **Source.** Use a song with a clear lead vocal; that vocal line is what the new lyrics are sung to. It must be at least 10 seconds long.
* **Lyrics.** New lyrics fit best when they follow the shape of the original: a similar number of lines per section, and similar line lengths.
* **Prompt.** Describe the new style: genre, mood, tempo, instruments and voice, separated by commas.
* **`n_variations`.** Ask for two or three when you want to choose; each costs the same as one.
* **Loudness.** Off unless you include the block. See the [loudness normalisation guide](/guides/adapt/normalise_loudness#choosing-a-target-by-destination) for which target to pick.

***

## Errors

**When you submit** (the request is refused, nothing is charged):

| Status | `type` | Why |
| - | - | - |
| `422` | `string_too_short` / `string_too_long` | `lyrics` is empty or over 3,000 characters, or `prompt` is empty or over 1,024. |
| `422` | `missing` | `source`, `lyrics` or `prompt` is missing. |
| `422` | `source_too_large` | The source's server says the file is over 50 MB. (When it doesn't say, the size is checked during processing instead.) |
| `422` | `idempotency_key_reused` | The key was already used for a different endpoint. |
| `402` | `insufficient_credits` | Your balance is below 3 credits per variation. |

**While processing** (the operation finishes as `failed`, with an `error.code`):

| Code | Why |
| - | - |
| `source_has_no_vocals` | The source is valid audio, but no vocals could be found in it. Use [`create.remix_instrumental`](/guides/create/remix_instrumental) for music without vocals. |
| `tos_violation` | The lyrics, prompt or source were rejected by our content policy. |
| `source_unreachable` | The source URL couldn't be fetched. |
| `source_format_unsupported` | The file isn't WAV, MP3 or FLAC audio. |
| `source_too_short` | The audio is shorter than 10 seconds. |
| `source_too_long` | The audio is longer than 5 minutes. |
| `source_too_large` | The file is larger than 50 MB. |
| `internal_error`, `generation_timeout` | Something went wrong on our side. Resubmit with the same idempotency key. |

**Source limits for this endpoint:** WAV, MP3 or FLAC, from **10 seconds** to 5 minutes long, and at most 50 MB.

See [Errors](/errors) for the response shapes, and for the errors every endpoint can return (`401`, `403`, `429`).

***

## Cost

**3 credits per variation**, so `n_variations: 2` costs 6. Normalisation costs nothing extra. Resending a request with the same idempotency key is not charged again.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.