SDK Reference
Every method on OpenAPIClient and ListenHubClient, grouped by product, with signatures, endpoints, and what each returns.
This is the complete method reference for @marswave/listenhub-sdk. Methods are grouped by product. Each entry lists the signature, one line on what it does, and the underlying HTTP endpoint.
The SDK ships two clients. They share response handling (unwrap data on code 0, throw ListenHubError otherwise, auto-retry 429) but target different API surfaces and authenticate differently:
OpenAPIClient | ListenHubClient | |
|---|---|---|
| Auth | API key (Authorization: Bearer) | OAuth user access token |
| Base URL | https://api.marswave.ai/openapi | https://api.listenhub.ai/api |
| Acts as | Your account / key owner | The signed-in user |
| Use for | Servers, scripts, CI | User-facing apps |
OpenAPIClient is the public OpenAPI product — that surface is the focus of this reference. ListenHubClient is the OAuth client used by first-party apps; its methods are listed under ListenHubClient methods at the end.
Generation is asynchronous. A create* call returns an id immediately; poll the matching get* method until processStatus (or task status) leaves pending / generating. See Quickstart for the full loop.
Conventions used below:
- "Endpoint" paths are relative to the client base URL. For
OpenAPIClientthat ishttps://api.marswave.ai/openapi/. - Methods return the unwrapped
datapayload. The{ code, message, data }envelope is handled for you. - A few methods return a raw
Response(binary or streaming) — these are called out explicitly. - Never hard-code credit costs. Use the
estimate*Creditsmethods andgetSubscription()instead.
OpenAPIClient methods
Speakers
A voice is identified by its speakerId. List voices before creating any episode and pass the ids you want.
| Method | Endpoint | Returns | Notes |
|---|---|---|---|
listSpeakers(params?) | GET v1/speakers/list | { items: OpenAPISpeaker[] } | Available voices |
listSpeakers parameters:
| Param | Type | Notes |
|---|---|---|
language | string | Filter by language, e.g. en, zh, ja |
status | number | Availability filter |
Each OpenAPISpeaker carries speakerId, name, gender, language, demoAudioUrl, and an optional profile (pitch, speed, traits, styles, scenes, accent, description).
const { items } = await client.listSpeakers({ language: 'en' });
const speakerId = items[0].speakerId;Podcast
A podcast is a multi-speaker conversation generated from a query and/or sources. Create it, then poll getPodcast until processStatus is success.
| Method | Endpoint | Returns |
|---|---|---|
createPodcast(params) | POST v1/podcast/episodes | { episodeId } |
getPodcast(episodeId) | GET v1/podcast/episodes/{episodeId} | OpenAPIPodcastDetail |
createPodcastTextContent(params) | POST v1/podcast/episodes/text-content | { episodeId, message } |
generatePodcastAudio(episodeId, params?) | POST v1/podcast/episodes/{episodeId}/audio | { success, message, episodeId, status } |
getPodcastTextStream(episodeId, event) | GET v1/podcast/episodes/{episodeId}/text-stream | raw Response (stream) |
createPodcast parameters (OpenAPICreatePodcastParams):
| Param | Type | Notes |
|---|---|---|
query | string | What the episode should cover |
sources | Array<{ type: 'text' | 'url'; content: string }> | Grounding material; raw text or a page URL |
speakers | Array<{ speakerId: string }> | Required; one entry per voice |
language | string | Output language |
mode | string | Generation depth (e.g. quick, deep) |
The two-step text-then-audio flow lets you review or edit the script before paying for audio: createPodcastTextContent generates the script only, then generatePodcastAudio(episodeId, { scripts }) renders audio from scripts you optionally rewrite. getPodcastTextStream(episodeId, 'script' | 'outline') returns a streaming Response for live script/outline tokens.
OpenAPIPodcastDetail includes processStatus, title, outline, cover, audioUrl, audioStreamUrl, subtitlesUrl, scripts (per-speaker lines), credits, and failCode on failure.
Flow Speech / TTS
Flow speech turns text or a URL into narrated audio with one or more voices. TTS endpoints are lower-level: they synthesize speech from explicit scripts.
Flow speech
| Method | Endpoint | Returns |
|---|---|---|
createFlowSpeech(params) | POST v1/flow-speech/episodes | { episodeId } |
getFlowSpeech(episodeId) | GET v1/flow-speech/episodes/{episodeId} | OpenAPIFlowSpeechDetail |
createFlowSpeechTTS(params) | POST v1/flow-speech/episodes/tts | { episodeId } |
getFlowSpeechTextStream(episodeId, event) | GET v1/flow-speech/episodes/{episodeId}/text-stream | raw Response (stream) |
createFlowSpeech parameters (OpenAPICreateFlowSpeechParams):
| Param | Type | Notes |
|---|---|---|
sources | Array<{ type: 'text' | 'url'; content?: string; uri?: string }> | Required; content for text, uri for URL |
speakers | Array<{ speakerId: string }> | Required |
language | string | Output language |
mode | 'smart' | 'direct' | smart rewrites for narration; direct reads as-is |
createFlowSpeechTTS takes scripts: Array<{ content: string; speakerId: string }> plus an optional title, and renders the lines verbatim. event for the text stream is 'script' | 'outline'.
OpenAPIFlowSpeechDetail includes processStatus, title, outline, cover, audioUrl, audioStreamUrl, subtitlesUrl, scripts, and sourceProcessResult.
TTS / speech
| Method | Endpoint | Returns |
|---|---|---|
speech(params) | POST v1/speech | OpenAPISpeechResponse |
tts(params) | POST v1/tts | raw Response (audio bytes) |
audioSpeech(params) | POST v1/audio/speech | raw Response (audio bytes) |
speech takes scripts: Array<{ content: string; speakerId: string }> and returns a synchronous result: { audioUrl, audioDuration, subtitlesUrl?, taskId, credits }.
tts and audioSpeech are OpenAI-compatible single-voice synthesis. They take { input, voice, response_format? } where response_format is one of mp3 (default), opus, aac, flac, wav, pcm, and return the audio as a raw Response — read it with .arrayBuffer() or stream .body.
const res = await client.tts({ input: 'Hello world', voice: speakerId, response_format: 'mp3' });
const audio = Buffer.from(await res.arrayBuffer());Storybook (explainer / slides)
Storybook produces page-based visual content — explainer videos and slide decks. mode selects the format. Audio is optional via skipAudio.
| Method | Endpoint | Returns |
|---|---|---|
createStorybook(params) | POST v1/storybook/episodes | { episodeId } |
getStorybook(episodeId) | GET v1/storybook/episodes/{episodeId} | OpenAPIStorybookDetail |
generateStorybookVideo(episodeId) | POST v1/storybook/episodes/{episodeId}/video | { success } |
createStorybook parameters (OpenAPICreateStorybookParams):
| Param | Type | Notes |
|---|---|---|
sources | Array<{ type: 'text' | 'url'; content: string }> | Required grounding material |
speakers | Array<{ speakerId: string }> | Optional; needed only when generating audio |
mode | 'info' | 'story' | 'slides' | slides for a deck; info / story for explainers |
skipAudio | boolean | Visual-only output when true |
style | string | Visual style hint |
language | string | Output language |
After an episode succeeds, generateStorybookVideo(episodeId) renders a downloadable video from the pages. Poll getStorybook and watch videoStatus (not_generated → pending → success / fail); videoUrl appears on success.
OpenAPIStorybookDetail includes mode, processStatus, title, cover, audioUrl, audioDuration, videoUrl, videoStatus, and pages (each with text, pageNumber, imageUrl, audioTimestamp).
Image
Single-call image generation. There is no separate poll method on OpenAPIClient — the response carries the result.
| Method | Endpoint | Returns |
|---|---|---|
createImage(params) | POST v1/images/generation | OpenAPICreateImageResponse |
createImage parameters (OpenAPICreateImageParams):
| Param | Type | Notes |
|---|---|---|
provider | string | Required image provider |
model | string | Provider model |
prompt | string | Required text prompt |
referenceImages | Array<{ fileData?; inlineData? }> | Reference images — fileData: { fileUri, mimeType } or inlineData: { data, mimeType } (base64) |
imageConfig | { imageSize?; aspectRatio? } | imageSize: 1K | 2K | 4K; aspectRatio: 16:9 | 4:3 | 1:1 | 3:4 | 9:16 | 21:9 |
Video (SeeDance / HappyHorse + PixVerse)
Two video families share the same poll/list/estimate methods but have different create methods and parameters. SeeDance (doubao-seedance-2-*) and HappyHorse use a content array; PixVerse uses a capability-based shape.
SeeDance / HappyHorse
| Method | Endpoint | Returns |
|---|---|---|
createVideoGeneration(params) | POST v1/video-generation/generate | { taskId, status } |
getVideoGenerationTask(taskId) | GET v1/video-generation/tasks/{taskId} | OpenAPIVideoGenerationTaskDetail |
listVideoGenerationTasks(params?) | GET v1/video-generation/tasks | { items, page, pageSize, total } |
estimateVideoCredits(params) | POST v1/video-generation/estimate-credits | { tokens, credits } |
createVideoGeneration parameters (OpenAPICreateVideoGenerationParams):
| Param | Type | Notes |
|---|---|---|
model | 'doubao-seedance-2-pro' | 'doubao-seedance-2-fast' | 'happyhorse' | Defaults to a SeeDance model |
content | VideoContentItem[] | Required; mixed text / image / video / audio items (see below) |
resolution | '480p' | '720p' | '1080p' | 1080p only on doubao-seedance-2-pro; happyhorse has no 480p |
ratio | '16:9' | '4:3' | '1:1' | '3:4' | '9:16' | '21:9' | '4:5' | '5:4' | 4:5 / 5:4 only on happyhorse |
duration | number | Seconds; SeeDance min 4, HappyHorse min 3 |
generateAudio | boolean | Generate an audio track |
seed | number | Reproducibility seed |
inputVideoDuration | number | For video-edit input; SeeDance [2,15], HappyHorse [3,60] |
audioSetting | 'auto' | 'origin' | HappyHorse video-edit only, when content includes a video_url |
Each content item is one of:
{ type: 'text', text }{ type: 'image_url', image_url: { url }, role: 'first_frame' \| 'last_frame' \| 'reference_image' }{ type: 'video_url', video_url: { url }, role: 'reference_video' }{ type: 'audio_url', audio_url: { url }, role: 'reference_audio' }
HappyHorse rejects last_frame and audio_url content. estimateVideoCredits takes { model, resolution, duration, hasVideoInput?, inputVideoDuration?, ratio? }.
const { taskId } = await client.createVideoGeneration({
model: 'doubao-seedance-2-pro',
content: [{ type: 'text', text: 'A timelapse of a city at dusk' }],
resolution: '1080p',
duration: 5,
});PixVerse
| Method | Endpoint | Returns |
|---|---|---|
createPixVerseVideoGeneration(params) | POST v1/video-generation/pixverse/generate | { taskId, episodeId?, status } |
estimatePixVerseVideoCredits(params) | POST v1/video-generation/pixverse/estimate-credits | { tokens, credits } |
Poll and list PixVerse tasks with the same getVideoGenerationTask / listVideoGenerationTasks methods above.
createPixVerseVideoGeneration parameters (OpenAPICreatePixVerseVideoParams):
| Param | Type | Notes |
|---|---|---|
capability | 'text_to_video' | 'image_to_video' | 'transition' | 'multi_transition' | 'fusion' | 'restyle' | 'mimic' | 'lip_sync' | 'agent' | Required; selects the generation mode |
model | 'pixverse' | 'v6' | 'v5' | 'v4.5' | PixVerse model version |
language | 'zh' | 'en' | Service region; en international, zh mainland China |
prompt | string | Text prompt |
duration | number | Seconds (1–60; agent: 20/30/60) |
aspectRatio | '9:16' | '16:9' | '1:1' | '4:3' | '3:4' | Output aspect ratio |
quality | '360p' | '540p' | '720p' | '1080p' | mimic locked to 720p; agent needs 720p/1080p |
sourceTaskId | string | Reuse a prior succeeded task (restyle / lip_sync) |
images / videos / audios | Array<{ url; duration? }> | Input assets |
pixverse | OpenAPIPixVerseOptions | Capability-specific nested options |
The nested pixverse object covers agentType, motionMode, cameraMovement, templateId, multiTransition, imageReferences, tts, soundEffect*, lipSyncTts*, brandSticker, and introOutroClip. Relevance depends on capability. estimatePixVerseVideoCredits takes { capability, model?, language?, duration?, quality?, pixverse? } with a reduced pixverse shape for the estimate.
Music
Music endpoints default to the Mureka provider. Async endpoints return a task ({ taskId, taskType, status }); poll getMusicTask. Synchronous endpoints (recognizeMusic, describeMusic, stemMusic) return their result directly.
| Method | Endpoint | Returns | Sync? |
|---|---|---|---|
createMusicGenerate(params) | POST v1/music/generate | CreateMusicTaskResponse | async |
createMusicCover(params) | POST v1/music/cover | CreateMusicTaskResponse | async (deprecated) |
createMusicExtend(params) | POST v1/music/extend | CreateMusicTaskResponse | async |
createMusicRemix(params) | POST v1/music/remix | CreateMusicTaskResponse | async |
createMusicInstrumental(params) | POST v1/music/instrumental | CreateMusicTaskResponse | async |
createMusicSoundtrack(params) | POST v1/music/soundtrack | CreateMusicTaskResponse | async |
createMusicTrack(params) | POST v1/music/track | CreateMusicTaskResponse | async |
recognizeMusic(params) | POST v1/music/recognize | RecognizeMusicResponse | sync |
describeMusic(params) | POST v1/music/describe | DescribeMusicResponse | sync |
stemMusic(params) | POST v1/music/stem | StemMusicResponse | sync |
getMusicTask(taskId) | GET v1/music/tasks/{taskId} | MusicTaskDetail | — |
listMusicTasks(params?) | GET v1/music/tasks | { items, page, pageSize, total } | — |
Key create parameters:
createMusicGenerate:{ prompt?, lyrics?, model?, style?, title?, instrumental?, vocalId? }.modelis one ofauto,mureka-7.6,mureka-8,mureka-9,mureka-o2.createMusicExtend:{ uploadUrl, model, continueAt, prompt?, style?, title?, instrumental?, negativeTags?, vocalGender?, styleWeight?, weirdnessConstraint?, audioWeight? }.modelhere is a Suno version (V4,V4_5,V4_5PLUS,V4_5ALL,V5,V5_5).createMusicRemix:{ audio?, audioFilename?, audioUrl?, providerSongId?, lyrics, prompt }. Provide exactly one ofaudio/audioUrl/providerSongId. Prefer this over the deprecatedcreateMusicCover.createMusicInstrumental:{ prompt?, referenceAudio?, referenceAudioFilename?, model? }. ProvidepromptXORreferenceAudio.createMusicSoundtrack:{ image?, video?, prompt?, model? }. ProvideimageXORvideo.createMusicTrack:{ audio?, providerSongId?, generateType, prompt, lyrics?, vocalGender?, generateStart?, generateEnd? }.generateTypeselects the stem (Vocals,Instrumental,Drums, …);lyricsis required whengenerateTypeisVocals.
The multipart endpoints (remix, instrumental, soundtrack, track, recognize, describe, stem) take a Blob/File for the audio/image/video field. In Node 20+, wrap a buffer with new Blob([buffer]).
const { taskId } = await client.createMusicGenerate({
prompt: 'lo-fi hip hop, mellow, rainy night',
model: 'auto',
});
let task = await client.getMusicTask(taskId);
while (task.status === 'pending' || task.status === 'generating') {
await sleep(10_000);
task = await client.getMusicTask(taskId);
}
console.log(task.tracks[0]?.audioUrl);Synchronous results: recognizeMusic returns timestamped lyricsSections; describeMusic returns { description, tags, genres, instruments }; stemMusic returns { zipUrl, midiZipUrl, expiresAt } (links expire ~24h).
Content Extract
Extract readable content from a URL (article text, optional summary). Asynchronous: create, then poll.
| Method | Endpoint | Returns |
|---|---|---|
createContentExtract(params) | POST v1/content/extract | { taskId } |
getContentExtract(taskId) | GET v1/content/extract/{taskId} | OpenAPIContentExtractDetail |
createContentExtract parameters (OpenAPICreateContentExtractParams):
| Param | Type | Notes |
|---|---|---|
source | { type: 'url'; uri: string } | Required; the page to extract |
options | { summarize?; maxLength?; twitter? } | summarize adds a summary; twitter: { count? } for thread depth |
Poll getContentExtract until status is completed. The detail carries data.content, data.metadata, data.references, and credits.
Subscription
| Method | Endpoint | Returns |
|---|---|---|
getSubscription() | GET v1/user/subscription | OpenAPISubscriptionInfo |
Returns credit balance and plan info: totalAvailableCredits, the monthly/permanent/limited-time credit breakdown, resetAt, renewStatus, paidStatus, and subscriptionPlan. Use totalAvailableCredits to check your balance before an expensive job.
Files
OpenAPIClient has no dedicated file-upload method. To use a local file as input, host it at a public URL and pass that URL (for example as a source uri, a referenceImages.fileData.fileUri, or a video image_url.url). The presigned-upload flow lives on ListenHubClient — see Files below.
ListenHubClient methods
ListenHubClient authenticates with an OAuth user access token and targets https://api.listenhub.ai/api. It exposes the first-party app surface. The product shapes differ from OpenAPIClient: episodes use a nested template object, and creation methods are split per product (podcast, TTS, explainer, slides). Use this client only when each request runs under an individual signed-in user.
Auth & session
| Method | Endpoint | Returns |
|---|---|---|
connectInit(params) | POST v1/auth/connect/init | { sessionId, authUrl } |
connectToken(params) | POST v1/auth/connect/token | { accessToken, refreshToken, expiresIn } |
refresh(params) | POST v1/auth/token | { accessToken, refreshToken, expiresIn } |
revoke(params) | POST v1/auth/token/revoke | void |
connectInit({ callbackPort }) starts the device/OAuth flow and returns an authUrl to open; connectToken({ sessionId, code }) exchanges the result for tokens. refresh({ refreshToken }) rotates an expiring access token; revoke({ refreshToken }) invalidates it.
Speakers
| Method | Endpoint | Returns |
|---|---|---|
listSpeakers(params?) | GET v1/settings/speakers | { items: Speaker[] } |
Parameters: { language?, status? }. Note the return shape differs from OpenAPIClient — each Speaker exposes speakerInnerId (not speakerId), plus personality, accessType, and weight. The speakerInnerId is what the episode template.speakers array expects.
Podcast
| Method | Endpoint | Returns |
|---|---|---|
createPodcast(params) | POST v1/episodes/all-in-one | { episodeId } |
listPodcasts(params?) | GET v1/episodes (productId=aiPodcast) | ListEpisodesResponse |
createPodcast parameters (CreatePodcastParams):
| Param | Type | Notes |
|---|---|---|
type | 'podcast-solo' | 'podcast-duo' | Single or two-host |
query | string | Topic |
sources | ContentSource[] | { type: 'url' | 'text'; uri?; content? } |
template | { type: 'podcast'; mode; speakers; language } | mode: quick | deep | debate; speakers: speakerInnerId[]; language: en | zh | ja |
Flow Speech / TTS
| Method | Endpoint | Returns |
|---|---|---|
createTTS(params) | POST v1/episodes/flow-speech | { episodeId } |
listTTS(params?) | GET v1/episodes (productId=textToSpeech) | ListEpisodesResponse |
createTTS parameters (CreateTTSParams): { sources, template: { type: 'flowspeech', mode: 'smart' | 'direct', speakers, language } }.
Storybook (explainer / slides)
| Method | Endpoint | Returns |
|---|---|---|
createExplainerVideo(params) | POST v1/episodes/storybook | { episodeId } |
createSlides(params) | POST v1/episodes/storybook (mode: 'slides', skipAudio: true) | { episodeId } |
exportExplainerVideo(episodeId) | POST v1/episodes/{episodeId}/storybook/video | void |
listExplainerVideos(params?) | GET v1/episodes (productId=explainerVideo) | ListEpisodesResponse |
listSlides(params?) | GET v1/episodes (productId=slideDeck) | ListEpisodesResponse |
createExplainerVideo and createSlides share a shape: { query?, sources?, style?, styleOverride?, skipAudio?, imageConfig?, template }. The template carries type: 'storybook', mode (info / story for explainers, slides for decks), speakers, language, and optional style, size (2K / 4K), aspectRatio (16:9 / 9:16 / 1:1), pageCount. createSlides defaults skipAudio to true and fixes mode to slides. exportExplainerVideo triggers the downloadable video render.
Episodes (shared)
These work across all four products on ListenHubClient.
| Method | Endpoint | Returns |
|---|---|---|
getCreation(episodeId) | GET v5/episodes/{episodeId}/detail | EpisodeDetail |
deleteCreations(params) | DELETE v1/episodes | void |
getCreation returns the full EpisodeDetail (status, speakers, topicDetail with title/outline/audio/video/pages/scripts). deleteCreations({ ids }) batch-soft-deletes up to 100 episodes by id; passing a video episode id also soft-deletes its video task and refunds credits for any in-progress task. The per-product list* methods all hit GET v1/episodes with a productId filter and accept { page?, pageSize? }.
Image
| Method | Endpoint | Returns |
|---|---|---|
createAIImage(params) | POST v1/images | { imageId } |
getAIImage(imageId) | GET v1/images/{imageId} | AIImageItem |
listAIImages(params?) | GET v1/images | { items, pagination } |
deleteAIImages(params) | DELETE v1/images | void |
createAIImage parameters (CreateAIImageParams):
| Param | Type | Notes |
|---|---|---|
prompt | string | Required |
referenceImageUrls | string[] | Reference image URLs |
language | 'auto' | 'en' | 'ja' | 'ko' | 'hi' | 'zh' | 'pt' | 'es' | Prompt language |
aspectRatio | '1:1' | '2:3' | '3:2' | '3:4' | '4:3' | '9:16' | '16:9' | '21:9' | … | Output ratio |
imageSize | '1K' | '2K' | '4K' | Output resolution |
model | 'gemini-3-pro-image' | 'gemini-3.1-flash-image' | Image model |
isLossless | boolean | Lossless encoding |
enableSearch | boolean | Allow web search for grounding |
Generation is async — poll getAIImage(imageId) until status is terminal and imageUrl is set. deleteAIImages({ ids }) batch-soft-deletes up to 100 images (owner-scoped; unknown ids ignored).
Music
ListenHubClient exposes the same music method set as OpenAPIClient (same endpoints, same parameters): createMusicGenerate, createMusicCover, createMusicExtend, createMusicRemix, createMusicInstrumental, createMusicSoundtrack, createMusicTrack, recognizeMusic, describeMusic, stemMusic, getMusicTask, listMusicTasks. See Music above for parameters and the poll loop.
Lyrics
| Method | Endpoint | Returns |
|---|---|---|
createLyrics(params) | POST v1/lyrics/generate | { taskId, status } |
getLyricsTask(taskId) | GET v1/lyrics/tasks/{taskId} | LyricsTaskDetail |
listLyricsTasks(params?) | GET v1/lyrics/tasks | { items, page, pageSize, total } |
createLyrics({ prompt }) starts an async lyrics task; poll getLyricsTask until status is success, then read variants (each { text, title, status }).
Video Generation
ListenHubClient exposes the same video methods as OpenAPIClient, with one naming difference: the SeeDance/HappyHorse estimate method is estimateVideoGenerationCredits (vs. estimateVideoCredits on OpenAPIClient).
| Method | Endpoint | Returns |
|---|---|---|
createVideoGeneration(params) | POST v1/video-generation/generate | { taskId, status } |
getVideoGenerationTask(taskId) | GET v1/video-generation/tasks/{taskId} | VideoGenerationTaskDetail |
listVideoGenerationTasks(params?) | GET v1/video-generation/tasks | { items, page, pageSize, total } |
estimateVideoGenerationCredits(params) | POST v1/video-generation/estimate-credits | { tokens, credits } |
createPixVerseVideoGeneration(params) | POST v1/video-generation/pixverse/generate | { taskId, episodeId?, status } |
estimatePixVerseVideoCredits(params) | POST v1/video-generation/pixverse/estimate-credits | { tokens, credits } |
Parameters match the Video section above.
Subscription & user
| Method | Endpoint | Returns |
|---|---|---|
getCurrentUser() | GET v1/users/me | UserProfile |
getSubscription() | GET v1/users/subscription | SubscriptionInfo |
getSettings() | GET v2/settings | SettingsResponse |
Note the endpoint differs from OpenAPIClient (v1/users/subscription vs. v1/user/subscription). getSettings returns the user's saved per-product defaults (speakers, language, duration, mode, style images).
Checkin
| Method | Endpoint | Returns |
|---|---|---|
checkinSubmit() | POST v1/checkin | { checkinDate, rewardCredits } |
checkinStatus() | GET v1/checkin/status | CheckinStatusResponse |
Daily check-in for reward credits. checkinStatus reports hasCheckedInToday, lastCheckinTime, and monthlyCheckinCount.
Settings / API key
| Method | Endpoint | Returns |
|---|---|---|
getApiKey() | GET v1/settings/api-key | { key } |
regenerateApiKey() | POST v1/settings/api-key/regenerate | { key } |
Lets a signed-in user read or rotate their OpenAPI key. regenerateApiKey invalidates the previous key.
Files
| Method | Endpoint | Returns |
|---|---|---|
createFileUpload(params) | POST v1/files | { presignedUrl, fileUrl } |
getFileDownloadUrl(fileUrl) | GET v1/files | { downloadUrl } |
createFileUpload({ fileKey, contentType, category }) returns a presignedUrl to PUT the bytes to, plus the fileUrl to reference afterward. getFileDownloadUrl(fileUrl) resigns a stored file URL into a time-limited downloadUrl.
The client.api escape hatch
ListenHubClient exposes its underlying ky instance as client.api for endpoints the SDK does not wrap. It applies the same auth, base URL, and retry behavior, but you parse the response yourself. Paths are relative to the base URL — no leading / (a ky requirement):
const me = await client.api.get('v1/users/me').json();OpenAPIClient does not expose client.api. For an OpenAPI endpoint the SDK does not cover yet, call it with your own HTTP client using the same Authorization: Bearer header — see the OpenAPI reference.
Errors
Every method throws a ListenHubError on a non-zero code or an HTTP error. It carries status, code, and requestId — include requestId when reporting an issue.
import { ListenHubError } from '@marswave/listenhub-sdk';
try {
await client.getPodcast('nope');
} catch (err) {
if (err instanceof ListenHubError) {
console.error(`[${err.status}] code ${err.code} (request ${err.requestId})`);
} else {
throw err;
}
}Next steps
Configuration
Configure base URL, timeout, and retries for both SDK clients, and learn how response unwrapping, ListenHubError, and 429 auto-retry behave.
Examples
Eight runnable TypeScript recipes for the OpenAPIClient — podcast, flow speech, TTS, image, video, music, content extract, and error handling.