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

# Voice Changer

> Transform voice characteristics in audio recordings using AudioPod AI's advanced voice conversion technology powered by OpenVoice v2.

## Overview

AudioPod AI's Voice Changer API uses OpenVoice v2 technology to convert source audio to match target voice characteristics. Transform any speech recording to sound like a different voice while preserving the original speech content, timing, and emotional expression.

### Key Features

* **Voice Conversion**: Transform source audio to match target voice characteristics
* **Content Preservation**: Maintains original speech content, timing, and emotional expression
* **Multiple Voice Sources**: Use any completed voice profile as a target voice
* **High Quality Processing**: Advanced OpenVoice v2 technology for natural-sounding results
* **Public Voice Support**: Access to both user-owned and public voice profiles
* **Flexible Input**: Support for various audio formats (WAV, MP3, M4A, etc.)
* **Real-time Processing**: Fast conversion for production workflows

## Authentication

All endpoints require authentication:

* **API Key (Recommended)**: `X-API-Key: your_api_key` header
* **JWT Token**: `Authorization: Bearer your_jwt_token` (for session-based auth)

## Voice Conversion

### Convert Audio to Target Voice

Transform the voice characteristics in a source audio file to match a target voice profile.

<Tabs>
  <Tab title="POST">
    ```http theme={null}
    POST /api/v1/voice/voice-convert
    X-API-Key: {api_key}
    Content-Type: multipart/form-data

    file: (source audio file)
    voice_uuid: "550e8400-e29b-41d4-a716-446655440000"
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    # Convert audio to match target voice
    with open("source_speech.wav", "rb") as audio_file:
        response = requests.post(
            "https://api.audiopod.ai/api/v1/voice/voice-convert",
            headers={"X-API-Key": api_key},
            data={
                "voice_uuid": "550e8400-e29b-41d4-a716-446655440000"  # Target voice UUID
            },
            files={"file": audio_file}
        )

    if response.status_code == 200:
        conversion_job = response.json()
        job_id = conversion_job["id"]
        print(f"Voice conversion job created: {job_id}")
        print(f"Status: {conversion_job['status']}")
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.audiopod.ai/api/v1/voice/voice-convert" \
      -H "X-API-Key: $AUDIOPOD_API_KEY" \
      -F "file=@source_speech.wav" \
      -F "voice_uuid=550e8400-e29b-41d4-a716-446655440000"
    ```
  </Tab>
</Tabs>

**Parameters:**

* **`file`** (required): Source audio file containing speech to convert
* **`voice_uuid`** (required): UUID of the target voice profile to match

**Voice UUID Sources:**

* User's own custom voice profiles (from voice cloning)
* Public voice profiles available in the voice library
* Voice must have status "COMPLETED" and available audio file

**Response:**

```json theme={null}
{
  "id": 123,
  "status": "PROCESSING",
  "progress": 0,
  "source_type": "FILE",
  "original_filename": "source_speech.wav",
  "target_voice_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "target_voice_name": "Professional Speaker Voice",
  "conversion_method": "openvoice_v2",
  "created_at": "2024-01-15T10:30:00Z",
  "task_id": "celery_task_uuid_here",
  "user_id": "user_abc123def456"
}
```

## Job Management

### Get Conversion Status

Monitor the progress of voice conversion jobs.

<Tabs>
  <Tab title="GET">
    ```http theme={null}
    GET /api/v1/voice/convert/{conversion_id}/status
    X-API-Key: {api_key}
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    conversion_id = 123
    response = requests.get(
        f"https://api.audiopod.ai/api/v1/voice/convert/{conversion_id}/status",
        headers={"X-API-Key": api_key}
    )

    if response.status_code == 200:
        conversion_status = response.json()
        print(f"Status: {conversion_status['status']}")
        
        if conversion_status["status"] == "COMPLETED":
            print("Voice conversion complete!")
            print(f"Output path: {conversion_status.get('output_path')}")
            print(f"Original filename: {conversion_status.get('original_filename')}")
    ```
  </Tab>
</Tabs>

**Response (Completed Job):**

```json theme={null}
{
  "id": 123,
  "status": "COMPLETED",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:33:45Z",
  "completed_at": "2024-01-15T10:33:45Z",
  "output_path": "outputs/converted/uuid/voice_converted.wav",
  "error_message": null,
  "task_id": "celery_task_uuid_here",
  "source_path": "temp/uploads/uuid/source_speech.wav",
  "original_filename": "source_speech.wav",
  "conversion_metadata": {
    "voice_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "voice_id": 456,
    "voice_file_path": "voices/456/uuid/voice.wav",
    "duration": 45.2
  }
}
```

### List Conversion Jobs

Get all voice conversion jobs for the authenticated user.

<Tabs>
  <Tab title="GET">
    ```http theme={null}
    GET /api/v1/voice/convert/jobs?status=COMPLETED&limit=10
    X-API-Key: <api_key>
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    response = requests.get(
        "https://api.audiopod.ai/api/v1/voice/convert/jobs",
        headers={"X-API-Key": api_key},
        params={
            "status": "COMPLETED",      # Filter by status
            "limit": 10,
            "skip": 0
        }
    )

    if response.status_code == 200:
        jobs = response.json()
        for job in jobs:
            print(f"Job {job['id']}: {job['status']} - {job.get('original_filename', 'N/A')}")
            voice_uuid = job.get('conversion_metadata', {}).get('voice_uuid', 'N/A')
            print(f"  Target voice UUID: {voice_uuid}")
    ```
  </Tab>
</Tabs>

### Download Converted Audio

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    def download_converted_audio(conversion_id, api_key):
        """Download converted audio from completed job"""
        
        # Get conversion details
        response = requests.get(
            f"https://api.audiopod.ai/api/v1/voice/convert/{conversion_id}/status",
            headers={"X-API-Key": api_key}
        )
        
        if response.status_code != 200:
            return {"error": "Conversion not found"}
        
        conversion = response.json()
        
        if conversion["status"] != "COMPLETED":
            return {"error": f"Conversion not completed. Status: {conversion['status']}"}
        
        if not conversion.get("output_path"):
            return {"error": "No output file available"}
        
        # Note: The output_path is the S3 key. You would need to use your S3 service
        # or a separate download endpoint to get the actual file.
        
        return {
            "success": True,
            "output_path": conversion["output_path"],
            "original_filename": conversion.get("original_filename"),
            "target_voice_uuid": conversion.get("conversion_metadata", {}).get("voice_uuid"),
            "status": "File ready for download"
        }

    # Usage
    result = download_converted_audio(123, "your_api_key")
    if result.get("success"):
        print(f"Conversion completed: {result['output_path']}")
        print(f"Original file: {result['original_filename']}")
        print(f"Target voice UUID: {result['target_voice_uuid']}")
    ```
  </Tab>
</Tabs>

## Voice Profile Management

### Find Available Voices

Before converting, you can browse available voice profiles to use as targets.

```python theme={null}
# Get available voices for conversion
response = requests.get(
    "https://api.audiopod.ai/api/v1/voice/voice-profiles",
    headers={"X-API-Key": api_key},
    params={
        "voice_type": "CUSTOM",      # Filter by voice type
        "include_public": "true",    # Include public voices
        "limit": 20
    }
)

if response.status_code == 200:
    voices_data = response.json()
    print("Available voices for conversion:")
    for voice in voices_data["voices"]:
        if voice["is_custom"] or voice.get("is_public"):
            print(f"- {voice['name']} (UUID: {voice['voice_id']})")
            print(f"  Category: {voice['category']}")
            print(f"  Language: {voice['language']}")
            print(f"  Type: {'Custom' if voice['is_custom'] else 'Public'}")
            print()
```

## Use Cases & Examples

### Podcast Voice Consistency

```python theme={null}
def convert_podcast_guest_to_host_voice(guest_audio, host_voice_uuid, api_key):
    """Convert guest audio to match host voice for consistency"""
    
    print("Converting guest audio to match host voice...")
    
    with open(guest_audio, "rb") as audio_file:
        response = requests.post(
            "https://api.audiopod.ai/api/v1/voice/voice-convert",
            headers={"X-API-Key": api_key},
            data={"voice_uuid": host_voice_uuid},
            files={"file": audio_file}
        )
    
    if response.status_code != 200:
        return {"error": "Failed to start conversion"}
    
    job_data = response.json()
    job_id = job_data["id"]
    
    # Wait for completion
    import time
    while True:
        status_response = requests.get(
            f"https://api.audiopod.ai/api/v1/voice/convert/{job_id}/status",
            headers={"X-API-Key": api_key}
        )
        
        job_status = status_response.json()
        print(f"Progress: {job_status['progress']}%")
        
        if job_status["status"] == "COMPLETED":
            break
        elif job_status["status"] == "FAILED":
            return {"error": "Conversion failed"}
        
        time.sleep(5)
    
    # Download result
    output_url = job_status["output_url"]
    converted_filename = f"guest_as_host_{job_id}.wav"
    
    audio_response = requests.get(output_url)
    with open(converted_filename, "wb") as f:
        f.write(audio_response.content)
    
    return {
        "success": True,
        "job_id": job_id,
        "output_file": converted_filename,
        "original_duration": job_status["original_duration"],
        "processing_time": job_status["processing_stats"]["total_time"]
    }

# Usage
result = convert_podcast_guest_to_host_voice(
    "guest_interview.wav", 
    "host_voice_uuid_here",
    "your_api_key"
)

if result.get("success"):
    print(f"Guest voice converted successfully!")
    print(f"Output: {result['output_file']}")
    print(f"Processing time: {result['processing_time']:.1f}s")
```

### Content Localization

```python theme={null}
def localize_content_voice(source_audio, target_locale_voices, api_key):
    """Convert content to different regional voice variations"""
    
    localized_versions = {}
    
    for locale, voice_uuid in target_locale_voices.items():
        print(f"Creating {locale} version...")
        
        with open(source_audio, "rb") as audio_file:
            response = requests.post(
                "https://api.audiopod.ai/api/v1/voice/voice-convert",
                headers={"X-API-Key": api_key},
                data={"voice_uuid": voice_uuid},
                files={"file": audio_file}
            )
        
        if response.status_code == 200:
            job_data = response.json()
            localized_versions[locale] = {
                "job_id": job_data["id"],
                "status": "processing",
                "target_voice": job_data["target_voice_name"]
            }
    
    # Monitor all jobs
    completed_versions = {}
    
    while len(completed_versions) < len(localized_versions):
        for locale, job_info in localized_versions.items():
            if locale in completed_versions:
                continue
            
            status_response = requests.get(
                f"https://api.audiopod.ai/api/v1/voice/convert/{job_info['job_id']}/status",
                headers={"X-API-Key": api_key}
            )
            
            job_status = status_response.json()
            
            if job_status["status"] == "COMPLETED":
                # Download localized version
                audio_response = requests.get(job_status["output_url"])
                filename = f"content_{locale}_{job_info['job_id']}.wav"
                
                with open(filename, "wb") as f:
                    f.write(audio_response.content)
                
                completed_versions[locale] = {
                    "filename": filename,
                    "target_voice": job_status["target_voice_name"],
                    "duration": job_status["converted_duration"]
                }
                
                print(f"Completed {locale} version: {filename}")
        
        time.sleep(5)
    
    return completed_versions

# Usage - create multiple regional versions
locale_voices = {
    "US": "us_professional_voice_uuid",
    "UK": "uk_professional_voice_uuid", 
    "AU": "au_professional_voice_uuid"
}

versions = localize_content_voice(
    "original_content.wav",
    locale_voices,
    "your_api_key"
)

print("Localized versions created:")
for locale, info in versions.items():
    print(f"  {locale}: {info['filename']} ({info['duration']:.1f}s)")
```

### Voice Anonymization

```python theme={null}
def anonymize_voice_recording(source_audio, api_key):
    """Convert sensitive audio to an anonymous voice for privacy"""
    
    # Use a generic public voice for anonymization
    anonymous_voice_uuid = "public_generic_voice_uuid"
    
    with open(source_audio, "rb") as audio_file:
        response = requests.post(
            "https://api.audiopod.ai/api/v1/voice/voice-convert",
            headers={"X-API-Key": api_key},
            data={"voice_uuid": anonymous_voice_uuid},
            files={"file": audio_file}
        )
    
    job_id = response.json()["id"]
    
    # Wait for completion
    while True:
        status_response = requests.get(
            f"https://api.audiopod.ai/api/v1/voice/convert/{job_id}/status",
            headers={"X-API-Key": api_key}
        )
        
        job_status = status_response.json()
        if job_status["status"] == "COMPLETED":
            break
        time.sleep(3)
    
    # Download anonymized audio
    audio_response = requests.get(job_status["output_url"])
    anonymized_filename = f"anonymized_{job_id}.wav"
    
    with open(anonymized_filename, "wb") as f:
        f.write(audio_response.content)
    
    return {
        "anonymized_file": anonymized_filename,
        "original_content_preserved": True,
        "voice_anonymized": True,
        "duration": job_status["converted_duration"]
    }
```

## Error Handling

<AccordionGroup>
  <Accordion title="404 Not Found - Voice Not Available">
    **Causes:** - Target voice UUID doesn't exist - Voice is not accessible to user - Voice is not completed or ready
    **Solutions:** - Verify voice UUID is correct - Ensure voice is completed and has audio file available - Use public voices or your own custom voices
  </Accordion>

  <Accordion title="400 Bad Request - Invalid Audio">
    **Causes:** - Source audio file has no speech content - Unsupported audio format - Audio file corrupted
    **Solutions:** - Ensure audio contains clear speech - Use supported formats (WAV, MP3, M4A) - Verify file integrity
  </Accordion>

  <Accordion title="422 Processing Error - Conversion Failed">
    **Causes:** - Source audio quality too poor - Incompatible voice characteristics - Processing timeout
    **Solutions:** - Improve source audio quality - Try different target voice - Use shorter audio segments
  </Accordion>

  <Accordion title="402 Payment Required - Insufficient Credits">
    **Causes:** - Not enough credits for conversion duration
    **Solutions:** - Purchase additional credits - Check credit requirements for audio duration
  </Accordion>
</AccordionGroup>

## Best Practices

### Audio Quality Guidelines

For optimal voice conversion results:

```python theme={null}
# Audio requirements for best results
audio_guidelines = {
    "sample_rate": "16kHz or higher recommended",
    "format": "WAV preferred, MP3/M4A acceptable",
    "duration": "10 seconds to 10 minutes optimal",
    "content": "Clear speech without background music",
    "speaker": "Single speaker recommended",
    "noise": "Minimal background noise"
}

# Pre-processing recommendations
preprocessing_tips = [
    "Use noise reduction for noisy recordings",
    "Normalize audio levels for consistent volume",
    "Remove long silent periods to improve processing speed",
    "Separate speakers if multiple voices present"
]
```

### Target Voice Selection

```python theme={null}
def choose_optimal_target_voice(source_characteristics, available_voices):
    """Choose the best target voice for conversion"""
    
    recommendations = []
    
    for voice in available_voices:
        score = 0
        
        # Language match
        if voice["language"] == source_characteristics["language"]:
            score += 30
        
        # Gender match (if applicable)
        if voice["gender"] == source_characteristics.get("gender"):
            score += 20
        
        # Age range compatibility
        if voice["age_range"] == source_characteristics.get("age_range"):
            score += 15
        
        # Style appropriateness
        if voice["style"] in source_characteristics.get("preferred_styles", []):
            score += 25
        
        # Quality indicators
        if voice.get("usage_stats", {}).get("avg_rating", 0) >= 4.5:
            score += 10
        
        recommendations.append({
            "voice": voice,
            "compatibility_score": score,
            "reasons": []
        })
    
    # Sort by compatibility score
    recommendations.sort(key=lambda x: x["compatibility_score"], reverse=True)
    
    return recommendations[:5]  # Top 5 recommendations
```

## Pricing

Voice conversion pricing is based on audio duration:

| Service          | Cost               | Description                                        |
| ---------------- | ------------------ | -------------------------------------------------- |
| Voice Conversion | 990 credits/minute | Transform voice characteristics using OpenVoice v2 |

### Cost Examples

| Duration   | Credits | USD Cost |
| ---------- | ------- | -------- |
| 30 seconds | 495     | \$0.0659 |
| 2 minutes  | 1980    | \$0.2634 |
| 5 minutes  | 4950    | \$0.6584 |
| 10 minutes | 9900    | \$1.3167 |

### Cost Optimization Tips

1. **Pre-process audio** to remove silence and optimize duration
2. **Batch similar conversions** using the same target voice
3. **Test with shorter clips** before converting long content
4. **Use high-quality source audio** to avoid re-processing

## Next Steps

<Columns cols={2}>
  <Card title="Voice Management" icon="users" href="/api-reference/voice-management">
    Browse and manage available voice profiles for conversion.
  </Card>

  <Card title="Speech-to-Text" icon="waveform" href="/api-reference/speech-to-text">
    Extract text from converted audio for verification.
  </Card>
</Columns>
