ListenHubOpenAPI

Quick Start

Get your API key and make your first call in 5 minutes.

Prerequisites

Get an API key:

  1. Go to API Key settings
  2. Click Create API Key
  3. Copy and store the API key securely

The API key is only displayed once at creation. Copy and save it to a secure location immediately.

Set up environment variable:

Save your API key as an environment variable. All code examples in this guide reference it:

# Add to ~/.zshrc or ~/.bashrc to persist across sessions
export LISTENHUB_API_KEY="your_api_key_here"

For more setup options, see Authentication.

Make Your First Call

Verify API Key

Send a simple request to confirm the API key works:

curl -X GET "https://api.marswave.ai/openapi/v1/speakers/list?language=en" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
const response = await fetch('https://api.marswave.ai/openapi/v1/speakers/list?language=en', {
  headers: {
    'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
  },
});
const data = await response.json();
console.log(data);
import os
import requests

response = requests.get(
    'https://api.marswave.ai/openapi/v1/speakers/list',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    params={'language': 'en'}
)
data = response.json()
print(data)

Success response:

{
  "code": 0,
  "message": "",
  "data": {
    "items": [
      {
        "name": "Ethan",
        "speakerId": "EN-Man-General-01",
        "demoAudioUrl": "https://example.com/demo-ethan.mp3",
        "gender": "male",
        "language": "en"
      },
      {
        "name": "Sophia",
        "speakerId": "EN-Woman-General-01",
        "demoAudioUrl": "https://example.com/demo-sophia.mp3",
        "gender": "female",
        "language": "en"
      }
    ]
  }
}

Create Your First Podcast

Use quick mode to generate a single-speaker episode:

curl -X POST "https://api.marswave.ai/openapi/v1/podcast/episodes" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Give a concise introduction to the history of artificial intelligence.",
    "speakers": [{"speakerId": "EN-Man-General-01"}],
    "language": "en",
    "mode": "quick"
  }'
const response = await fetch('https://api.marswave.ai/openapi/v1/podcast/episodes', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    query: 'Give a concise introduction to the history of artificial intelligence.',
    speakers: [{ speakerId: 'EN-Man-General-01' }],
    language: 'en',
    mode: 'quick',
  }),
});
const data = await response.json();
console.log('Episode ID:', data.data.episodeId);
import os
import requests

response = requests.post(
    'https://api.marswave.ai/openapi/v1/podcast/episodes',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    json={
        'query': 'Give a concise introduction to the history of artificial intelligence.',
        'speakers': [{'speakerId': 'EN-Man-General-01'}],
        'language': 'en',
        'mode': 'quick',
    }
)
data = response.json()
print('Episode ID:', data['data']['episodeId'])

Success response:

{
  "code": 0,
  "message": "",
  "data": {
    "episodeId": "{episodeId}"
  }
}

Podcast generation is asynchronous. The episodeId is the identifier you use to track generation progress.

Query Generation Result

Poll the status using the returned episodeId:

curl -X GET "https://api.marswave.ai/openapi/v1/podcast/episodes/{episodeId}" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
const response = await fetch(
  'https://api.marswave.ai/openapi/v1/podcast/episodes/{episodeId}',
  {
    headers: { 'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}` },
  }
);
const data = await response.json();
console.log('Status:', data.data.processStatus);
import os
import requests

response = requests.get(
    'https://api.marswave.ai/openapi/v1/podcast/episodes/{episodeId}',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'}
)
data = response.json()
print('Status:', data['data']['processStatus'])

Response while processing (processStatus is pending):

{
  "code": 0,
  "message": "",
  "data": {
    "episodeId": "{episodeId}",
    "createdAt": 1760517419993,
    "failCode": 0,
    "processStatus": "pending",
    "credits": 0,
    "sourceProcessResult": {
      "content": "Give a concise introduction to the history of artificial intelligence.",
      "references": []
    },
    "title": "",
    "outline": "",
    "cover": "https://static.listenhub.ai/listenhub_default_cover061802.png",
    "audioUrl": "",
    "scripts": []
  }
}

Response after completion (processStatus is success):

{
  "code": 0,
  "message": "",
  "data": {
    "episodeId": "{episodeId}",
    "createdAt": 1760517752411,
    "failCode": 0,
    "processStatus": "success",
    "credits": 27,
    "sourceProcessResult": {
      "content": "Give a concise introduction to the history of artificial intelligence.",
      "references": []
    },
    "title": "A Brief History of Artificial Intelligence",
    "outline": "...",
    "cover": "https://static.listenhub.ai/listenhub_default_cover061804.png",
    "audioUrl": "https://assets.listenhub.ai/listenhub-public-prod/podcast/{episodeId}.mp3",
    "scripts": [
      {
        "speakerId": "EN-Man-General-01",
        "speakerName": "Ethan",
        "content": "Artificial intelligence has evolved from symbolic logic to modern large models..."
      }
    ]
  }
}

When processStatus becomes success, the audioUrl field contains the final MP3 audio URL.

Polling Best Practices

Podcast generation typically takes 1-4 minutes. Recommended polling strategy: wait 60 seconds before the first poll, then poll every 10 seconds.

async function pollEpisodeResult(episodeId, apiKey, timeout = 300000) {
  const url = `https://api.marswave.ai/openapi/v1/podcast/episodes/${episodeId}`;
  const headers = { 'Authorization': `Bearer ${apiKey}` };
  const startTime = Date.now();

  // Generation takes time, wait 60 seconds first
  await new Promise(resolve => setTimeout(resolve, 60000));

  while (Date.now() - startTime < timeout) {
    const response = await fetch(url, { headers });
    const data = await response.json();

    if (data.code !== 0) throw new Error(`API error: ${data.message}`);

    const status = data.data.processStatus;
    if (status === 'success') return data.data;
    if (status === 'failed') throw new Error(`Generation failed: ${data.data.message}`);

    await new Promise(resolve => setTimeout(resolve, 10000));
  }
  throw new Error('Episode generation timeout');
}
import time
import os
import requests

def poll_episode_result(episode_id, api_key, timeout=300):
    """Poll episode result until completion. Default timeout is 5 minutes."""
    url = f"https://api.marswave.ai/openapi/v1/podcast/episodes/{episode_id}"
    headers = {"Authorization": f"Bearer {api_key}"}

    start_time = time.time()

    # Generation takes time, wait 60 seconds first
    time.sleep(60)

    while time.time() - start_time < timeout:
        response = requests.get(url, headers=headers)
        data = response.json()

        if data["code"] != 0:
            raise Exception(f"API error: {data['message']}")

        status = data["data"]["processStatus"]

        if status == "success":
            return data["data"]
        if status == "failed":
            raise Exception(f"Generation failed: {data['data'].get('message')}")

        time.sleep(10)

    raise TimeoutError("Episode generation timeout")

Next Steps

On this page