ListenHub OpenAPI

Quick Start

Prerequisites, first API call, and polling best practices.

1. Quick Start in 5 Minutes

1. Prerequisites

Plan requirement:

  • OpenAPI is available to all users.

Get an API key:

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

2. Make the First API Call

2.1 Verify API Key

Test whether the API key works:

curl -X GET "https://api.marswave.ai/openapi/v1/speakers/list?language=en" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example 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"
      }
    ]
  }
}

2.2 Create the First Podcast Episode

Use quick mode to generate a single-speaker episode: The example below uses EN-Man-General-01, and any valid speaker from GET /v1/speakers/list can be used.

curl -X POST "https://api.marswave.ai/openapi/v1/podcast/episodes" \
  -H "Authorization: Bearer YOUR_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"
  }'

Example success response:

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

2.3 Query Generation Result

Use the returned episodeId to query status:

curl -X GET "https://api.marswave.ai/openapi/v1/podcast/episodes/<EPISODE_ID>" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response while processing:

{
  "code": 0,
  "message": "",
  "data": {
    "episodeId": "68ef5d2b5d59db3b0909c08c",
    "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:

{
  "code": 0,
  "message": "",
  "data": {
    "episodeId": "68ef5e78e06b4dd24fbfe69f",
    "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/68ef5e78e06b4dd24fbfe69d.mp3",
    "scripts": [
      {
        "speakerId": "EN-Man-General-01",
        "speakerName": "Ethan",
        "content": "Artificial intelligence has evolved from symbolic logic to modern large models..."
      }
    ]
  }
}

3. Polling Best Practices

Recommended polling strategy:

  • Wait 60 seconds before first polling
  • Poll every 10 seconds
  • Stop when processStatus becomes success or failed
import time
import requests

def poll_episode_result(episode_id, api_key, timeout=300):
    """
    Poll one episode result until completion.

    Args:
        episode_id: Episode ID
        api_key: API key
        timeout: Timeout in seconds, default 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()
    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")

Polling policy: wait 1 minute, then poll every 10 seconds.

On this page