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

# Stem Separation

> Extract individual audio components from mixed recordings using AI-powered audio source separation.

## Overview

AudioPod AI's Stem Separation API uses state-of-the-art AI models to separate mixed audio recordings into individual components (stems). Extract vocals, drums, bass, guitar, piano, and more from any song.

### Key Features

* **Granular Separation**: `two`, `four`, `six`, plus the detailed `producer`, `studio`, and `mastering` decompositions
* **Single-Instrument Isolation**: Target one instrument from a 45-instrument catalog and get it back alongside an everything-else track
* **File Upload & URL Support**: Process local files or YouTube/SoundCloud URLs
* **Quality Scores**: Get AI-assessed quality metrics for each stem
* **Presigned Downloads**: Direct S3 URLs for fast stem downloads

## Installation

<Tabs>
  <Tab title="Python">
    ```bash theme={null}
    pip install audiopod
    ```
  </Tab>

  <Tab title="Node.js">
    ```bash theme={null}
    npm install audiopod
    ```
  </Tab>
</Tabs>

## Authentication

Get your API key from the [API Keys Dashboard](https://www.audiopod.ai/dashboard/account/api-keys).

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")
    # Or set AUDIOPOD_API_KEY environment variable
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });
    // Or set AUDIOPOD_API_KEY environment variable
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    export AUDIOPOD_API_KEY="ap_your_api_key"
    # Use -H "X-API-Key: $AUDIOPOD_API_KEY" in requests
    ```
  </Tab>
</Tabs>

## Separation Modes

Pass one of these as `mode` to `POST /api/v1/stem-extraction/api/extract`.

| Mode | Output | Plan | Use Case |
| - | - | - | - |
| `single` | One named stem + everything-else | Basic | Vocal isolation, drum extraction |
| `two` | vocals + instrumental | Basic | Karaoke tracks |
| `four` | vocals, drums, bass, other | Basic | Standard remixing |
| `six` | + guitar, piano | Basic | Full instrument separation |
| `producer` | Drums split into kick, snare, hi-hat — up to 8 | Creator | Beat production |
| `studio` | Full drum kit plus a bass frequency split — up to 12 | Pro | Professional mixing |
| `mastering` | Full kit, bass split, and vocal stereo separation — up to 16 | Pro | Maximum detail |

<Info>
  **Counts are a ceiling, not a promise.** `producer`, `studio`, and `mastering`
  decompose whatever is actually in the recording, so the stem count depends on
  the track — a song with no cymbals yields no cymbal stem. Plan for "up to N".
</Info>

<Warning>
  **Plan gating.** `producer` requires **Creator** or above; `studio` and
  `mastering` require **Pro** or above. A request from a lower plan is rejected —
  call `GET /api/v1/stem-extraction/packages/available` to see what the
  authenticated key can use before you dispatch a job.
</Warning>

For `mode="single"` this endpoint accepts the six core stems — `vocals`,
`drums`, `bass`, `guitar`, `piano`, `other`. To reach the full instrument
catalog, use the advanced endpoint below.

***

## The 45-Instrument Catalog

Beyond the fixed modes, you can name **one** instrument out of a 45-entry
catalog and get that instrument back plus an everything-else track. The 45 is
the size of the menu you can choose from — not the number of files a job
returns.

Use `POST /api/v1/stem-extraction/extract/advanced` with `single_stem` set to a
catalog id. The service resolves the right processing path and plan check for
you, so you never pick an engine.

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    # Isolate the saxophone from a track
    curl -X POST https://api.audiopod.ai/api/v1/stem-extraction/extract/advanced \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "url=https://youtube.com/watch?v=VIDEO_ID" \
      -F "single_stem=saxophone"
    ```
  </Tab>

  <Tab title="Exclude one instrument">
    ```bash theme={null}
    # Everything EXCEPT the saxophone (JSON array, one id)
    curl -X POST https://api.audiopod.ai/api/v1/stem-extraction/extract/advanced \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "url=https://youtube.com/watch?v=VIDEO_ID" \
      -F 'exclude_stems=["saxophone"]'
    ```
  </Tab>
</Tabs>

### Discover the catalog at runtime

Don't hard-code the list — plan gating and catalog contents change. `GET
/api/v1/stem-extraction/catalog` returns every stem with the plan it needs and
whether the authenticated key can use it right now:

```bash theme={null}
curl -s https://api.audiopod.ai/api/v1/stem-extraction/catalog \
  -H "X-API-Key: $AUDIOPOD_API_KEY"
```

Each entry carries an `id` (what you send as `single_stem`), a `label` and
`description` for your UI, a `group`, the `public_tier` it requires, an
`allowed` boolean for the current key, and `excludable` (whether it can be used
with `exclude_stems`).

### Catalog contents

**Core — available on every plan including Basic (7)**

`vocals` · `backing_track` · `drums` · `bass` · `guitar` · `piano` · `other`

**Specialty vocals — Creator and above (4)**

`lead_vocal` · `backing_vocal` · `male_vocal` · `female_vocal`

**Instruments — Creator and above (34)**

`acoustic_guitar` · `electric_guitar` · `lead_guitar` · `rhythm_guitar` ·
`bagpipes` · `banjo` · `bassoon` · `brass` · `braam` · `celesta` · `cello` ·
`choir` · `clarinet` · `double_bass` · `flute` · `french_horn` · `fx` · `harp` ·
`harmonica` · `keys` · `mandolin` · `oboe` · `organ` · `percussion` ·
`plucked_strings` · `strings` · `saxophone` · `trombone` · `trumpet` · `tuba` ·
`viola` · `violin` · `woodwind` · `xylophone`

<Warning>
  Requesting a Creator-tier stem with a Basic key is rejected. Check `allowed` on
  the catalog response first, or handle the error and prompt for an upgrade.
</Warning>

<Info>
  **Pricing.** Catalog isolation is metered per minute of audio like every other
  stem job. A few premium selections carry a multiplier — see
  [API Wallet & Pricing](/account/api-wallet).
</Info>

***

## Quick Start

### Six-Stem Separation

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    # Extract and wait for completion
    result = client.stems.separate(
        url="https://youtube.com/watch?v=VIDEO_ID",
        mode="six"
    )

    # Download stems
    print("Stems ready:")
    for stem, url in result["download_urls"].items():
        print(f"  {stem}: {url[:60]}...")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    // Extract and wait for completion
    const result = await client.stems.separate({
      url: 'https://youtube.com/watch?v=VIDEO_ID',
      mode: 'six'
    });

    // Download stems
    console.log('Stems ready:');
    for (const [stem, url] of Object.entries(result.download_urls)) {
      console.log(`  ${stem}: ${url.substring(0, 60)}...`);
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # Submit job
    curl -X POST "https://api.audiopod.ai/api/v1/stem-extraction/api/extract" \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "url=https://youtube.com/watch?v=VIDEO_ID" \
      -F "mode=six"

    # Check status (replace JOB_ID)
    curl -X GET "https://api.audiopod.ai/api/v1/stem-extraction/status/JOB_ID" \
      -H "X-API-Key: $AUDIOPOD_API_KEY"
    ```
  </Tab>
</Tabs>

***

## Examples by Mode

### Four-Stem Separation (Standard)

Extract vocals, drums, bass, and other.

<Tabs>
  <Tab title="Python (URL)">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    result = client.stems.separate(
        url="https://youtube.com/watch?v=VIDEO_ID",
        mode="four"
    )

    print(f"Vocals: {result['download_urls']['vocals']}")
    print(f"Drums: {result['download_urls']['drums']}")
    print(f"Bass: {result['download_urls']['bass']}")
    print(f"Other: {result['download_urls']['other']}")
    ```
  </Tab>

  <Tab title="Python (File)">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    result = client.stems.separate(
        file="/path/to/song.mp3",
        mode="four"
    )

    for stem, url in result["download_urls"].items():
        print(f"{stem}: {url}")
    ```
  </Tab>

  <Tab title="Node.js (URL)">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    const result = await client.stems.separate({
      url: 'https://youtube.com/watch?v=VIDEO_ID',
      mode: 'four'
    });

    console.log(`Vocals: ${result.download_urls.vocals}`);
    console.log(`Drums: ${result.download_urls.drums}`);
    console.log(`Bass: ${result.download_urls.bass}`);
    console.log(`Other: ${result.download_urls.other}`);
    ```
  </Tab>

  <Tab title="Node.js (File)">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    const result = await client.stems.separate({
      file: '/path/to/song.mp3',
      mode: 'four'
    });

    for (const [stem, url] of Object.entries(result.download_urls)) {
      console.log(`${stem}: ${url}`);
    }
    ```
  </Tab>

  <Tab title="cURL (URL)">
    ```bash theme={null}
    curl -X POST "https://api.audiopod.ai/api/v1/stem-extraction/api/extract" \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "url=https://youtube.com/watch?v=VIDEO_ID" \
      -F "mode=four"
    ```
  </Tab>

  <Tab title="cURL (File)">
    ```bash theme={null}
    curl -X POST "https://api.audiopod.ai/api/v1/stem-extraction/api/extract" \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "file=@/path/to/song.mp3" \
      -F "mode=four"
    ```
  </Tab>
</Tabs>

***

### Single Stem Extraction (Vocals Only)

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    # Extract only vocals
    result = client.stems.separate(
        url="https://youtube.com/watch?v=VIDEO_ID",
        mode="single",
        stem="vocals"  # Options: vocals, drums, bass, guitar, piano, other
    )

    print(f"Vocals: {result['download_urls']['vocals']}")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    // Extract only vocals
    const result = await client.stems.separate({
      url: 'https://youtube.com/watch?v=VIDEO_ID',
      mode: 'single',
      stem: 'vocals' // Options: vocals, drums, bass, guitar, piano, other
    });

    console.log(`Vocals: ${result.download_urls.vocals}`);
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.audiopod.ai/api/v1/stem-extraction/api/extract" \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "url=https://youtube.com/watch?v=VIDEO_ID" \
      -F "mode=single" \
      -F "stem=vocals"
    ```
  </Tab>
</Tabs>

***

### Two-Stem Separation (Karaoke)

Separate vocals from instrumental.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    result = client.stems.separate(
        url="https://youtube.com/watch?v=VIDEO_ID",
        mode="two"
    )

    # Returns: vocals + no_vocals (instrumental)
    print(f"Vocals: {result['download_urls']['vocals']}")
    print(f"Instrumental: {result['download_urls']['no_vocals']}")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    const result = await client.stems.separate({
      url: 'https://youtube.com/watch?v=VIDEO_ID',
      mode: 'two'
    });

    // Returns: vocals + no_vocals (instrumental)
    console.log(`Vocals: ${result.download_urls.vocals}`);
    console.log(`Instrumental: ${result.download_urls.no_vocals}`);
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.audiopod.ai/api/v1/stem-extraction/api/extract" \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "url=https://youtube.com/watch?v=VIDEO_ID" \
      -F "mode=two"
    ```
  </Tab>
</Tabs>

***

### Producer Mode (8 Stems with Drum Kit)

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    result = client.stems.separate(
        url="https://youtube.com/watch?v=VIDEO_ID",
        mode="producer"
    )

    # Returns: vocals, kick, snare, hihat, bass, guitar, piano, other
    for stem, url in result["download_urls"].items():
        print(f"{stem}: {url[:60]}...")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    const result = await client.stems.separate({
      url: 'https://youtube.com/watch?v=VIDEO_ID',
      mode: 'producer'
    });

    // Returns: vocals, kick, snare, hihat, bass, guitar, piano, other
    for (const [stem, url] of Object.entries(result.download_urls)) {
      console.log(`${stem}: ${url.substring(0, 60)}...`);
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.audiopod.ai/api/v1/stem-extraction/api/extract" \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "url=https://youtube.com/watch?v=VIDEO_ID" \
      -F "mode=producer"
    ```
  </Tab>
</Tabs>

***

## Advanced Usage

### Async Job Handling

For more control, use `extract()` and `wait_for_completion()` separately:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    # Submit job (returns immediately)
    job = client.stems.extract(
        url="https://youtube.com/watch?v=VIDEO_ID",
        mode="six"
    )
    print(f"Job submitted: {job['id']}")

    # Do other work...

    # Wait for completion when ready
    result = client.stems.wait_for_completion(job["id"], timeout=600)

    if result["status"] == "COMPLETED":
        print("Download URLs:")
        for stem, url in result["download_urls"].items():
            print(f"  {stem}: {url}")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    // Submit job (returns immediately)
    const job = await client.stems.extract({
      url: 'https://youtube.com/watch?v=VIDEO_ID',
      mode: 'six'
    });
    console.log(`Job submitted: ${job.id}`);

    // Do other work...

    // Wait for completion when ready
    const result = await client.stems.waitForCompletion(job.id, 600000);

    if (result.status === 'COMPLETED') {
      console.log('Download URLs:');
      for (const [stem, url] of Object.entries(result.download_urls)) {
        console.log(`  ${stem}: ${url}`);
      }
    }
    ```
  </Tab>
</Tabs>

### Get Available Modes

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    modes = client.stems.modes()

    print("Available modes:")
    for m in modes["modes"]:
        print(f"  {m['mode']}: {m['description']} ({m['stem_count']} stems)")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    const modes = await client.stems.modes();

    console.log('Available modes:');
    modes.modes.forEach(m => {
      console.log(`  ${m.mode}: ${m.description} (${m.stem_count} stems)`);
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.audiopod.ai/api/v1/stem-extraction/modes"
    ```
  </Tab>
</Tabs>

### Check Job Status

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod

    client = AudioPod(api_key="ap_your_api_key")

    status = client.stems.status(5512)

    print(f"Status: {status['status']}")

    if status["status"] == "COMPLETED":
        print("Quality scores:")
        for stem, score in status["quality_scores"].items():
            print(f"  {stem}: {score:.2f}")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod from 'audiopod';

    const client = new AudioPod({ apiKey: 'ap_your_api_key' });

    const status = await client.stems.status(5512);

    console.log(`Status: ${status.status}`);

    if (status.status === 'COMPLETED') {
      console.log('Quality scores:');
      for (const [stem, score] of Object.entries(status.quality_scores)) {
        console.log(`  ${stem}: ${score.toFixed(2)}`);
      }
    }
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.audiopod.ai/api/v1/stem-extraction/status/5512" \
      -H "X-API-Key: $AUDIOPOD_API_KEY"
    ```
  </Tab>
</Tabs>

***

## Response Format

**Completed Job Response:**

```json theme={null}
{
  "id": 5512,
  "status": "COMPLETED",
  "source_type": "URL",
  "stem_paths": {
    "vocals": "stems/5512/vocals.wav",
    "drums": "stems/5512/drums.wav",
    "bass": "stems/5512/bass.wav",
    "guitar": "stems/5512/guitar.wav",
    "piano": "stems/5512/piano.wav",
    "other": "stems/5512/other.wav"
  },
  "quality_scores": {
    "vocals": 0.64,
    "drums": 0.35,
    "bass": 0.87,
    "guitar": 0.38,
    "piano": 0.0,
    "other": 0.36
  },
  "download_urls": {
    "vocals": "https://media.audiopod.ai/...",
    "drums": "https://media.audiopod.ai/...",
    "bass": "https://media.audiopod.ai/...",
    "guitar": "https://media.audiopod.ai/...",
    "piano": "https://media.audiopod.ai/...",
    "other": "https://media.audiopod.ai/..."
  },
  "completed_at": "2025-12-11T12:39:37.379848"
}
```

***

## Pricing

**Base rate:** \$0.10 per minute of audio processed for every standard mode —
`single`, `two`, `four`, `six`, `producer`, `studio`, `mastering`.

| Duration | Cost (standard modes) |
| - | - |
| 3 minutes | \$0.30 |
| 5 minutes | \$0.50 |
| 10 minutes | \$1.00 |
| 1 hour | \$6.00 |

### Prices by output group

Different output groups add together. Selecting one or both outputs within a vocal pair costs the same. Lead and rhythm guitar also share one specialist group.

| Selected output group | Developer API wallet | Studio credits |
| - | - | - |
| Core vocals and instruments | \$0.10/min | 660/min |
| Lead + backing vocals | \$0.15/min together | 990/min together |
| Male + female vocals | \$0.15/min together | 990/min together |
| Other specialist instrument groups | \$0.20/min each | 1,320/min each |

All four vocal specialties total **$0.30/min on the API** or **1,980 Studio credits/min**. Adding core instruments totals **$0.40/min** or **2,640 Studio credits/min**. These are separate payment systems; API dollars are not a conversion of subscription credits.

Creator unlocks specialty vocals and the instrument catalog. Pro and Studio provide larger credit allowances; detailed decomposition presets require Pro. All public plans meter usage.

Read `GET /api/v1/stem-extraction/pricing` for the current group rate card. For credit-funded Studio jobs, `POST /api/v1/stem-extraction/quote` returns the measured duration, each group's price and the complete total. It does not quote API-wallet jobs. Studio quotes round duration up to whole seconds, then round the total down to whole credits; minimum charges apply. Group line items sum to that total and can differ by one credit due to allocation rounding.

Review the full quote before starting. Credits are reserved at creation. Groups that fail to deliver every requested output are refunded. A missing-output retry has its own quote; it is not permission to charge again for outputs already delivered.

<Info>
  Check your balance and usage at [API Wallet](/account/api-wallet).
</Info>

***

## Error Handling

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from audiopod import AudioPod, InsufficientBalanceError, AuthenticationError

    try:
        client = AudioPod(api_key="ap_...")
        result = client.stems.separate(url="...", mode="six")
    except AuthenticationError:
        print("Invalid API key")
    except InsufficientBalanceError as e:
        print(f"Need ${e.required_cents / 100:.2f}, have ${e.available_cents / 100:.2f}")
    except ValueError as e:
        print(f"Invalid input: {e}")
    ```
  </Tab>

  <Tab title="Node.js">
    ```typescript theme={null}
    import AudioPod, { InsufficientBalanceError, AuthenticationError } from 'audiopod';

    try {
      const client = new AudioPod({ apiKey: 'ap_...' });
      const result = await client.stems.separate({ url: '...', mode: 'six' });
    } catch (error) {
      if (error instanceof AuthenticationError) {
        console.log('Invalid API key');
      } else if (error instanceof InsufficientBalanceError) {
        console.log(`Need $${error.requiredCents / 100}, have $${error.availableCents / 100}`);
      } else {
        console.log(`Error: ${error.message}`);
      }
    }
    ```
  </Tab>
</Tabs>

***

## Status Codes

| Status | Description |
| - | - |
| `PENDING` | Job queued, waiting for worker |
| `PROCESSING` | Stem separation in progress |
| `COMPLETED` | Success - download URLs available |
| `FAILED` | Error occurred - check error\_message |

***

## Next Steps

<Columns cols={2}>
  <Card title="API Wallet" icon="wallet" href="/account/api-wallet">
    Manage billing and view usage history.
  </Card>

  <Card title="Noise Reduction" icon="volume-xmark" href="/api-reference/noise-reduction">
    Clean up stems for better quality.
  </Card>
</Columns>


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