ListenHubOpenAPI
API Reference

Content Extract

Asynchronously extract text content from URLs including web articles, Twitter/X profiles, tweets, YouTube videos, and WeChat Official Account posts.

Content Extract

Extract text content from any URL asynchronously. Submit a URL to create a task, then poll for the result.

Supported Sources

X / Twitter

Profile pages and individual tweets — fetch recent posts from any public account, or extract a single tweet with its full context.

YouTube

Extract video transcripts and metadata from any public YouTube video URL.

WeChat Official Accounts

Extract article content from WeChat Official Account posts (mp.weixin.qq.com).

Web Articles

Any publicly accessible web page — article text, metadata, and reference links.

Use Cases

  • Podcast source material -- extract articles, tweets, or WeChat posts as input for podcast generation
  • Content summarization -- pull long-form content and generate a summary in one call with summarize
  • Social media monitoring -- batch-extract tweets from key accounts
  • Research aggregation -- collect and structure content from multiple URLs

Create Extraction Task

POST /v1/content/extract

Submitting a task is non-blocking: the endpoint validates the request, reserves credits, kicks off extraction, and returns a taskId immediately. Use Query Task Status to retrieve the result.

Request example:

curl -X POST "https://api.marswave.ai/openapi/v1/content/extract" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "type": "url",
      "uri": "https://example.com/article"
    }
  }'
const response = await fetch('https://api.marswave.ai/openapi/v1/content/extract', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    source: {
      type: 'url',
      uri: 'https://example.com/article',
    },
  }),
});
const data = await response.json();
const taskId = data.data.taskId;
console.log('Task ID:', taskId);
import os
import requests

response = requests.post(
    'https://api.marswave.ai/openapi/v1/content/extract',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    json={
        'source': {
            'type': 'url',
            'uri': 'https://example.com/article',
        }
    }
)
data = response.json()
task_id = data['data']['taskId']
print('Task ID:', task_id)

With options (summarize + max length):

Set summarize: true to have the extracted text condensed into an AI summary, and maxLength to cap the number of characters returned.

curl -X POST "https://api.marswave.ai/openapi/v1/content/extract" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "type": "url",
      "uri": "https://example.com/long-article"
    },
    "options": {
      "summarize": true,
      "maxLength": 5000
    }
  }'
const response = await fetch('https://api.marswave.ai/openapi/v1/content/extract', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    source: {
      type: 'url',
      uri: 'https://example.com/long-article',
    },
    options: {
      summarize: true,
      maxLength: 5000,
    },
  }),
});
const data = await response.json();
console.log(data);
import os
import requests

response = requests.post(
    'https://api.marswave.ai/openapi/v1/content/extract',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    json={
        'source': {
            'type': 'url',
            'uri': 'https://example.com/long-article',
        },
        'options': {
            'summarize': True,
            'maxLength': 5000,
        },
    }
)
data = response.json()
print(data)

Twitter/X profile URL with tweet count:

# For Twitter/X profile URLs, use the twitter option to control how many tweets to fetch
curl -X POST "https://api.marswave.ai/openapi/v1/content/extract" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "type": "url",
      "uri": "https://x.com/elonmusk"
    },
    "options": {
      "twitter": {
        "count": 50
      }
    }
  }'
const response = await fetch('https://api.marswave.ai/openapi/v1/content/extract', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    source: {
      type: 'url',
      uri: 'https://x.com/elonmusk',
    },
    options: {
      twitter: {
        count: 50,
      },
    },
  }),
});
const data = await response.json();
console.log(data);
import os
import requests

response = requests.post(
    'https://api.marswave.ai/openapi/v1/content/extract',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    json={
        'source': {
            'type': 'url',
            'uri': 'https://x.com/elonmusk',
        },
        'options': {
            'twitter': {
                'count': 50,
            },
        },
    }
)
data = response.json()
print(data)

WeChat Official Account article:

curl -X POST "https://api.marswave.ai/openapi/v1/content/extract" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "type": "url",
      "uri": "https://mp.weixin.qq.com/s/XXXXXXXXXXXXXXXX"
    }
  }'
const response = await fetch('https://api.marswave.ai/openapi/v1/content/extract', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    source: {
      type: 'url',
      uri: 'https://mp.weixin.qq.com/s/XXXXXXXXXXXXXXXX',
    },
  }),
});
const data = await response.json();
const taskId = data.data.taskId;
import os
import requests

response = requests.post(
    'https://api.marswave.ai/openapi/v1/content/extract',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    json={
        'source': {
            'type': 'url',
            'uri': 'https://mp.weixin.qq.com/s/XXXXXXXXXXXXXXXX',
        }
    }
)
data = response.json()
task_id = data['data']['taskId']

Request body:

FieldTypeRequiredDescription
sourceobjectYesSource to extract from
source.typestringYesMust be "url"
source.uristringYesThe URL to extract content from
optionsobjectNoExtraction options (defaults to {})
options.summarizebooleanNoGenerate an AI summary of the extracted text (default false)
options.maxLengthintegerNoMaximum content length in characters (default 100000, min 1, max 500000)
options.twitterobjectNoTwitter/X specific options
options.twitter.countintegerNoNumber of tweets to fetch from a profile URL (1100, default 20)

Response example:

{
  "code": 0,
  "message": "success",
  "data": {
    "taskId": "67f6a1b2c3d4e5f6a7b8c9d0"
  }
}

The taskId is a 24-character hex string. Pass it to the status endpoint below.


Query Task Status

GET /v1/content/extract/{taskId}

Poll this endpoint until status is completed or failed. While the task is still running, the response carries only the status — the extracted content is withheld until extraction and credit settlement finish.

Request example:

curl -X GET "https://api.marswave.ai/openapi/v1/content/extract/67f6a1b2c3d4e5f6a7b8c9d0" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
const result = await fetch(`https://api.marswave.ai/openapi/v1/content/extract/${taskId}`, {
  headers: {
    'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
  },
});
const data = await result.json();
console.log('Status:', data.data.status);
import os
import requests

result = requests.get(
    f'https://api.marswave.ai/openapi/v1/content/extract/{task_id}',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'}
)
data = result.json()
print('Status:', data['data']['status'])

Path parameters:

FieldTypeDescription
taskIdstring24-character hex string returned by the create endpoint

Response while processing (status: "processing"):

{
  "code": 0,
  "message": "success",
  "data": {
    "taskId": "67f6a1b2c3d4e5f6a7b8c9d0",
    "status": "processing",
    "createdAt": 1744200000000
  }
}

The data object (extracted content) is omitted until the task completes.

Response when complete (status: "completed"):

{
  "code": 0,
  "message": "success",
  "data": {
    "taskId": "67f6a1b2c3d4e5f6a7b8c9d0",
    "status": "completed",
    "createdAt": 1744200000000,
    "data": {
      "content": "The extracted article text content...",
      "metadata": {
        "title": "Article Title",
        "author": "Author Name"
      },
      "references": [
        "https://example.com/related-article"
      ]
    },
    "credits": 100
  }
}

Response on failure (status: "failed"):

{
  "code": 0,
  "message": "success",
  "data": {
    "taskId": "67f6a1b2c3d4e5f6a7b8c9d0",
    "status": "failed",
    "createdAt": 1744200000000,
    "failCode": 1001,
    "message": "Failed to extract content from URL"
  }
}

Response fields:

FieldTypeDescription
taskIdstringTask identifier
statusstringprocessing, completed, or failed
createdAtintegerCreation time as a 13-digit epoch-millisecond timestamp
dataobjectExtracted content. Present only when status is completed
data.contentstringExtracted text content (summarized when summarize: true)
data.metadataobjectPage metadata such as title and author
data.referencesarrayReferenced URLs found in the content
creditsintegerCredits consumed (present when status is completed)
failCodeintegerError code (present when status is failed)
messagestringError description (present when status is failed)

Notes

Twitter/X profile URLs:

  • When the source URL is a Twitter/X profile (e.g. https://x.com/username), the API fetches recent tweets.
  • Use options.twitter.count to control how many tweets to retrieve (1100, default 20).
  • This option is ignored for non-Twitter URLs.

WeChat Official Accounts:

  • Use the full mp.weixin.qq.com/s/... article URL.
  • Extracted content includes the article body text and metadata.

Task lifecycle:

StatusDescription
processingExtraction is in progress
completedContent extracted successfully
failedExtraction failed -- check failCode and message

Polling recommendations:

  • Initial wait: 5 seconds after task creation
  • Poll interval: 5 seconds
  • Typical completion time: 10-30 seconds depending on URL complexity

Credits:

Content extraction reserves credits when the task starts and settles to the actual amount once the content length is known. The credits field in the completed response reflects the final charge.

RuleDetails
Pre-deductionA small hold is reserved when the task starts
Actual chargeBased on the number of characters in the extracted content, capped by maxLength
Failure refundAll reserved credits are refunded if extraction fails

Content extraction itself has no estimate endpoint — the final credits value is known only after the content length settles. Check your live balance with GET /v1/user/subscription, and see Pricing for the credit-to-feature mapping.


On this page