npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

myvoicemaker

v0.1.1

Published

Official JavaScript/TypeScript SDK for the VoiceMaker API

Readme

myvoicemaker

Official JavaScript / TypeScript SDK for the VoiceMaker API.

Generate dialect-accurate speech, transcribe audio in Nigerian languages, create lip-sync animations, and more — all from a single, fully typed client.

npm version License: MIT


Table of Contents


Installation

npm install myvoicemaker

Requires Node.js 18+ (uses native fetch). No other runtime dependencies.


Quick Start

import { VoiceMaker } from 'myvoicemaker';

const client = new VoiceMaker({ apiKey: 'vmk_live_...' });

// Generate speech
const tts = await client.tts.generate({
  text: 'Bawo ni o se wa?',
  voice_id: 'masoyinbo-male-conversational',
  language: 'yo',
});
console.log(tts.audio_url);

// Transcribe an audio file
const job = await client.asr.transcribeFile('./sermon.mp3', { language: 'yo' });
const result = await client.asr.poll(job.job_id, { timeoutMs: 120_000 });
console.log(result.text);

Authentication

All requests require a developer API key passed as a Bearer token. Create and manage your keys from the VoiceMaker Developer Dashboard.

const client = new VoiceMaker({ apiKey: 'vmk_live_...' });

| Key environment | Prefix | Credits consumed | | :--- | :--- | :--- | | Production | vmk_live_ | Yes | | Test / Sandbox | vmk_test_ | No |

Keep your API key secret. Use environment variables in production:

const client = new VoiceMaker({ apiKey: process.env.VOICEMAKER_API_KEY! });

Configuration options

const client = new VoiceMaker({
  apiKey: 'vmk_live_...',
  baseUrl: 'https://api.myvoicemaker.ai', // default
  timeoutMs: 30_000,                       // default: 30 seconds
});

Supported Languages

| Language | Code | Auto-detect (ASR) | | :--- | :--- | :---: | | Yoruba | yo | ✓ | | Igbo | ig | ✓ | | Hausa | ha | ✓ | | Nigerian Pidgin | pcm | ✓ | | English | en | ✓ | | Auto-detect | auto | — |


Modules

Text-to-Speech (TTS)

Convert text into natural-sounding speech. Requests are synchronous — the audio URL is returned immediately.

client.tts.listVoices(params?)

Retrieve all available voices, optionally filtered by language.

const { voices } = await client.tts.listVoices({ language: 'yo' });

for (const voice of voices) {
  console.log(`${voice.id} — ${voice.name} (${voice.gender}, ${voice.style})`);
  console.log(`  Sample: ${voice.sample_url}`);
}

Parameters

| Parameter | Type | Description | | :--- | :--- | :--- | | language | string (optional) | Filter by language code: yo, ig, ha, pcm, en |

Returns VoiceListResponse

| Field | Type | | :--- | :--- | | voices | Voice[] |

Each Voice has: id, name, gender, language, style, sample_url.


client.tts.generate(params)

const result = await client.tts.generate({
  text: 'Nne, ka anyị bido oge a.',
  voice_id: 'sunday-okafor-male-conversational',
  language: 'ig',
  speed: 0.9,
  output_format: 'mp3',
});

console.log(result.audio_url);      // https://media.myvoicemaker.ai/...
console.log(result.duration_seconds); // e.g. 3.2
console.log(result.credits_used);     // e.g. 28

Parameters

| Parameter | Type | Required | Description | | :--- | :--- | :---: | :--- | | text | string | ✓ | Text to synthesise (max 5,000 characters) | | voice_id | string | ✓ | Voice identifier from listVoices() | | language | string | ✓ | Language code | | speed | number | | Playback speed: 0.52.0 (default 1.0) | | output_format | string | | mp3 | wav | ogg (default mp3) |

Returns TtsGenerateResponse

| Field | Type | | :--- | :--- | | id | string | | audio_url | string | | duration_seconds | number \| null | | characters | number | | credits_used | number | | language | string | | voice_id | string | | created_at | string (ISO 8601) |


Automatic Speech Recognition (ASR)

Transcribe pre-recorded audio files. Jobs are asynchronous — submit a job, then poll for the result.

client.asr.transcribe(params) — from URL

const job = await client.asr.transcribe({
  audio: 'https://storage.example.com/interview.wav',
  language: 'ha',
  webhookUrl: 'https://myapp.com/webhooks/voicemaker',
});
console.log(job.job_id);  // use this to poll

Parameters

| Parameter | Type | Required | Description | | :--- | :--- | :---: | :--- | | audio | string | ✓ | Publicly accessible URL of the audio file | | language | string | | Language code or auto (default) | | webhookUrl | string | | Callback URL when the job completes |


client.asr.transcribeFile(filePath, params?) — from file

const job = await client.asr.transcribeFile('./hausa-interview.mp3', {
  language: 'ha',
});

Parameters

| Parameter | Type | Required | Description | | :--- | :--- | :---: | :--- | | filePath | string | ✓ | Absolute or relative path to the audio file | | language | string | | Language code or auto (default) | | webhookUrl | string | | Callback URL when the job completes |

Supported formats: .mp3, .wav, .ogg, .m4a, .webm — max 500 MB.


client.asr.getResult(jobId)

const result = await client.asr.getResult('trans_1a2b3c...');
console.log(result.status); // 'queued' | 'processing' | 'completed' | 'failed'
console.log(result.text);

client.asr.list(params?)

const page = await client.asr.list({ limit: 10, status: 'COMPLETED' });

for (const job of page.items) {
  console.log(`${job.job_id}: ${job.text?.slice(0, 60)}`);
}

// Load the next page
if (page.nextCursor) {
  const next = await client.asr.list({ cursor: page.nextCursor });
}

Parameters

| Parameter | Type | Description | | :--- | :--- | :--- | | limit | number | Items per page: 1–100 (default 20) | | cursor | string | Pagination cursor from a previous response | | status | string | Filter: QUEUED | PROCESSING | COMPLETED | FAILED |


client.asr.poll(jobId, options?) — wait for completion

Polls getResult at a regular interval until the job reaches a terminal state (completed or failed).

const result = await client.asr.poll(job.job_id, {
  intervalMs: 3_000,   // poll every 3 seconds (default: 2 000)
  timeoutMs: 120_000,  // give up after 2 minutes (default: 120 000)
});

if (result.status === 'completed') {
  console.log(`Transcript: ${result.text}`);
  console.log(`Language detected: ${result.detected_language}`);
  console.log(`Duration: ${result.duration_seconds}s`);
}

Throws TimeoutError if timeoutMs is exceeded before the job completes.

TranscriptionJob shape

| Field | Type | | :--- | :--- | | job_id | string | | status | 'queued' \| 'processing' \| 'completed' \| 'failed' | | language | string | | detected_language | string \| null | | text | string \| null | | confidence | number \| null | | duration_seconds | number \| null | | credits_used | number \| null | | created_at | string (ISO 8601) | | completed_at | string \| null (ISO 8601) |


Lip-Sync Animation

Generate a lip-sync video by combining a portrait image with an audio file. Jobs are asynchronous.

client.animate.generate(params)

const job = await client.animate.generate({
  image_url: 'https://example.com/speaker-portrait.jpg',
  audio_url: tts.audio_url,
  output_format: 'mp4',
});
console.log(job.job_id);
console.log(`Estimated credits: ${job.estimated_credits}`);

Parameters

| Parameter | Type | Required | Description | | :--- | :--- | :---: | :--- | | image_url | string | ✓ | URL of the source portrait image (max 5 MB, up to 4K) | | audio_url | string | ✓ | URL of the audio file (max 30 seconds) | | output_format | string | | mp4 | webm (default mp4) |


client.animate.getResult(jobId)

const result = await client.animate.getResult('anim_1a2b3c...');
console.log(result.status);    // 'queued' | 'processing' | 'completed' | 'failed'
console.log(result.video_url); // null until completed

client.animate.poll(jobId, options?)

const result = await client.animate.poll(job.job_id, {
  intervalMs: 5_000,
  timeoutMs: 300_000,
});

if (result.status === 'completed') {
  console.log(`Video: ${result.video_url}`);
  console.log(`Duration: ${result.duration_seconds}s`);
}

Explain

Process text in Nigerian languages — explain, summarise, translate, or simplify content using AI.

Note: This module targets a planned endpoint. Check the changelog for availability.

client.explain.process(params)

const result = await client.explain.process({
  text: 'Ìwé Mímọ̀ sọ pé...',
  language: 'yo',
  action: 'translate',
  target_language: 'en',
  max_tokens: 500,
});

console.log(result.result);       // translated text
console.log(result.tokens_used);  // e.g. 145
console.log(result.credits_used); // e.g. 145

Parameters

| Parameter | Type | Required | Description | | :--- | :--- | :---: | :--- | | text | string | ✓ | Input text to process | | language | string | ✓ | Source language code | | action | string | ✓ | explain | summarize | translate | simplify | | target_language | string | | Required when action is translate | | max_tokens | number | | Response length limit: 1–2000 (default 500) |


Usage & Billing

client.usage.getBalance()

const balance = await client.usage.getBalance();

console.log(`Tier:              ${balance.tier}`);
console.log(`Credits remaining: ${balance.credits_remaining.toLocaleString()}`);
console.log(`Credits used:      ${balance.credits_used.toLocaleString()}`);

Returns UsageBalanceResponse

| Field | Type | | :--- | :--- | | account_id | string | | tier | 'free' \| 'starter' \| 'growth' \| 'pro' \| 'enterprise' | | credits_remaining | number | | credits_used | number | | credits_total | number (present only if credits were ever purchased) | | credits_expire | string \| null | | created_at | string (ISO 8601) |


client.usage.getBreakdown(params)

const report = await client.usage.getBreakdown({
  start_date: '2026-05-01T00:00:00Z',
  end_date:   '2026-05-31T23:59:59Z',
  module:     'asr', // optional filter
});

for (const entry of report.breakdown) {
  console.log(`${entry.module}: ${entry.requests} requests, ${entry.credits_used} credits`);
}
console.log(`Total: ${report.total_credits_used} credits`);

Parameters

| Parameter | Type | Required | Description | | :--- | :--- | :---: | :--- | | start_date | string | ✓ | ISO 8601 datetime (inclusive) | | end_date | string | ✓ | ISO 8601 datetime (inclusive) | | module | string | | Filter: tts | asr | animate | explain |


Error Handling

Every API error is thrown as a typed exception that extends VoiceMakerAPIError.

import {
  VoiceMakerError,
  AuthenticationError,
  InsufficientCreditsError,
  RateLimitError,
  ValidationError,
  NotFoundError,
  TimeoutError,
} from 'myvoicemaker';

try {
  const result = await client.tts.generate({ ... });
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error('Invalid or expired API key');
  } else if (err instanceof InsufficientCreditsError) {
    console.error('Not enough credits. Top up at myvoicemaker.ai/billing');
  } else if (err instanceof RateLimitError) {
    const wait = err.retryAfter ?? 60;
    console.error(`Rate limited. Retry in ${wait}s`);
  } else if (err instanceof ValidationError) {
    console.error('Invalid parameters:', err.issues);
  } else if (err instanceof TimeoutError) {
    console.error(`Job ${err.jobId} timed out after ${err.timeoutMs}ms`);
  } else if (err instanceof VoiceMakerError) {
    console.error(`API error ${err.status}: ${err.detail}`);
  }
}

Error classes

| Class | HTTP Status | Description | | :--- | :--- | :--- | | AuthenticationError | 401 | Missing or invalid API key | | InsufficientCreditsError | 402 | Insufficient purchased credits | | PermissionError | 403 | Key lacks required scope or plan | | NotFoundError | 404 | Resource not found | | FileSizeLimitError | 413 | Audio file exceeds plan size limit | | UnsupportedMediaTypeError | 415 | Unsupported file format | | ValidationError | 422 | Invalid request parameters (check .issues) | | RateLimitError | 429 | Rate limit or concurrency limit exceeded | | ServerError | 500/503 | Internal server error | | TimeoutError | — | poll() timed out waiting for job completion |

All HTTP error classes expose:

err.status      // HTTP status code
err.error       // Short error title from the API
err.detail      // Human-readable explanation
err.requestId   // Request ID for support (from X-Request-Id header)
err.issues      // Validation issues array (ValidationError only)

Polling Async Jobs

ASR and Animation jobs are processed asynchronously. The SDK's poll() helper handles the retry loop for you:

// Submit
const job = await client.asr.transcribeFile('./audio.mp3', { language: 'en' });

// Poll until done
const result = await client.asr.poll(job.job_id, {
  intervalMs: 2_000,   // how often to check (default: 2 000 ms)
  timeoutMs: 120_000,  // maximum wait time (default: 120 000 ms)
});

Alternatively, manage polling manually:

let result = await client.asr.getResult(job.job_id);

while (result.status === 'queued' || result.status === 'processing') {
  await new Promise(r => setTimeout(r, 3000));
  result = await client.asr.getResult(job.job_id);
}

TypeScript

The SDK is written in TypeScript and ships with full type declarations. No additional @types packages are needed.

import type {
  VoiceMakerConfig,
  TranscriptionJob,
  TtsGenerateResponse,
  AnimateResultResponse,
  VoiceListResponse,
  Voice,
  UsageBalanceResponse,
  SupportedLanguage,
  JobStatus,
  PollOptions,
} from 'myvoicemaker';

All response objects, request parameters, error classes, and union literals are exported directly from the package root.


Rate Limits

Rate limits are enforced per API key and vary by plan:

| Plan | Requests / min | Concurrent jobs | | :--- | :--- | :--- | | Growth | 60 | 5 | | Pro | 120 | 10 | | Enterprise | Custom | Custom |

When a limit is exceeded the SDK throws RateLimitError. The Retry-After header value (seconds) is available as err.retryAfter.

Each API response also includes rate limit metadata in the response headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset).


Credit Costs

| Module | Billable unit | Cost | | :--- | :--- | :--- | | TTS | Input characters | 1 credit / character | | ASR | Audio duration | 5 credits / second | | Animate | Video duration | 50 credits / second | | Explain | LLM tokens | 1 credit / token |


License

MIT © Collins Edim