> ## 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.

# Auto cut-down

> Trim a track to a target length at musically natural cut points

`adapt.auto_cut_down` shortens (or lengthens) a piece of music to a length you choose, cutting at points that sound natural instead of fading out mid-phrase. Use it to fit a track to a 30-second advert, a 15-second social clip, or the length of a voiceover.

***

## The request

| Field | Required | What it is |
| - | - | - |
| `source` | yes | The track: `{"url": "https://..."}`, a public link to a WAV, MP3 or FLAC file. |
| `target_duration` | yes | The length you want, in seconds, from `5` to `300`, and at most twice the source's length. |
| `loudness` | no | Normalise the cut to a target loudness, at no extra cost. Leave it out to get the cut as it is. 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/adapt/auto_cut_down/submit) and [poll](/api-reference/adapt/auto_cut_down/poll) in the API Reference.

***

## Example

This cuts a track down to 30 seconds for an advert, normalised for streaming. It uses the [reference client](/client); save `soundpiece.py` or `soundpiece.mjs` next to it first.

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

cut = soundpiece.run("adapt.auto_cut_down", {
    "source": {"url": "https://example.com/audio/track.mp3"},
    "target_duration": 30,
    "loudness": {"preset": "streaming"},
})

soundpiece.download(cut["output"]["url"], "cut.flac")
print(f"Saved cut.flac ({cut['output']['duration']} seconds)")
```

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

const cut = await run("adapt.auto_cut_down", {
  source: { url: "https://example.com/audio/track.mp3" },
  target_duration: 30,
  loudness: { preset: "streaming" },
});

await download(cut.output.url, "cut.flac");
console.log(`Saved cut.flac (${cut.output.duration} seconds)`);
```

```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/track.mp3" },
  target_duration: 30,
  loudness: { preset: "streaming" }
}')
response=$(curl --silent --show-error --max-time 30 --request PUT "$API/adapt.auto_cut_down" \
  --header "$AUTH" --header "Content-Type: application/json" --data "$body")
result=$(jq -e .auto_cut <<<"$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/adapt.auto_cut_down?id=$id&wait=true" \
    --header "$AUTH")
  result=$(jq -e .auto_cut <<<"$response") || { echo "$response"; exit 1; }
done

# 3. Download, or show what went wrong.
if [ "$(jq -r .status <<<"$result")" = failed ]; then
  jq .error <<<"$result"
  exit 1
fi
curl --silent --show-error --fail --output cut.flac "$(jq -r .output.url <<<"$result")"
echo "Saved cut.flac"
```

***

## The result

`run` returns the finished `auto_cut` object:

```json theme={null}
{
  "id": "op_01ks2q0f8ewz3t6m1n4b7c9d2a",
  "status": "ready",
  "created_at": "2026-10-10T09:15:02Z",
  "idempotency_key": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
  "target_duration": 30.0,
  "loudness": { "target_lufs": -14.0, "allow_compression": true, "preset": "streaming" },
  "output": {
    "url": "https://cdn.soundpiece.co/...signed...",
    "expires_at": "2026-10-10T09:31:40Z",
    "duration": 30.6,
    "loudness": { "lufs": -14.0, "true_peak_dbtp": -1.4, "compressed": false }
  },
  "error": null
}
```

| Field | What it means |
| - | - |
| `target_duration` | The length you asked for. |
| `loudness` | Present only if you asked for normalisation: the target, and `preset` when you named one. |
| `output.url` | A signed link to the cut, as a FLAC file (44.1 kHz). It needs no API key. |
| `output.expires_at` | When the link stops working. Poll the operation again for a fresh one. |
| `output.duration` | The cut's real length in seconds. It can be slightly shorter or longer than `target_duration`, so that it ends on a natural boundary. |
| `output.loudness` | Present only if you asked for normalisation: `lufs`, `true_peak_dbtp` and `compressed`, measured on the cut. |

***

## Choosing parameters

* **`target_duration` is a target, not an exact length.** The cut lands near it, on a natural boundary. If you need an exact length (to the frame), trim or pad the result yourself afterwards.
* **It can lengthen too.** A target longer than the source makes a longer version, up to twice the source's length.
* **Loudness** is off unless you include the block. Add it when the cut is going straight to a platform; it costs nothing extra. 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` | `greater_than_equal` / `less_than_equal` | `target_duration` is under 5 or over 300 seconds. |
| `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 1 credit. |

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

| Code | Why |
| - | - |
| `target_duration_too_long` | `target_duration` is more than twice the source's length. This is only known once the source has been fetched, so it can't be refused up front. |
| `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 2.5 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 **2.5 seconds** to 5 minutes long, and at most 50 MB. The minimum is higher than elsewhere because the shortest cut, 5 seconds, needs a source at least half that long.

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

***

## Cost

**1 credit** per request, with or without normalisation. 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.