API Reference

Base URL: https://api.leanvox.com

Authentication

All API requests require an API key passed via the Authorization header.

Authorization: Bearer lv_live_YOUR_API_KEY

Generate API keys from the dashboard. Keys use the lv_live_ prefix and are hashed server-side — save them when created.

Register

POST /v1/auth/register
{ "email": "you@example.com", "password": "your-password" }

Login

POST /v1/auth/login
{ "email": "you@example.com", "password": "your-password" }

Returns: { "token": "jwt...", "user": { "id", "email" } }

Generate Speech

POST /v1/tts/generate
{
  "text": "Hello world!",
  "model": "standard",     // "standard" or "pro"
  "voice": "af_heart",     // voice ID
  "language": "en",        // ISO 639-1 code
  "format": "mp3",         // optional: "mp3" (default) or "wav"
  "speed": 1.0,            // optional: 0.5 - 2.0
  "exaggeration": 0.5      // optional (pro only): 0.0 - 1.0
}

Response

{
  "audio_url": "https://cdn.leanvox.com/audio/abc123.mp3",
  "model": "standard",
  "voice": "af_heart",
  "characters": 12,
  "cost_cents": 0.06
}

Models

ModelEnginePriceFeatures
standardKokoro 82M$0.005/1KFast, 54+ voices, 10 languages
proChatterbox 350M$0.01/1KVoice cloning, emotion tags, 23 languages

Dialogue (Pro only)

Generate multi-speaker dialogue in a single request. Pro model only.

POST /v1/tts/dialogue
{
  "model": "pro",
  "lines": [
    { "text": "Hi there!", "voice": "emma", "language": "en" },
    { "text": "Hello! [laugh]", "voice": "james", "language": "en", "exaggeration": 0.7 }
  ],
  "gap_ms": 500    // silence between lines (default 500)
}

Voices

List Voices

GET /v1/voices?model=standard

Clone Voice (Pro)

POST /v1/voices/clone
{
  "name": "My Voice",
  "audio_base64": "<base64-encoded WAV>",
  "description": "optional description"
}

Upload a 5-30 second WAV clip. Returns a voice_id for use with the Pro model.

Delete Voice

DELETE /v1/voices/{voice_id}

Async Jobs

For long texts, use async generation. You get a job ID immediately and poll for completion.

Create Async Job

POST /v1/tts/generate/async

Same body as /v1/tts/generate. Optional "webhook_url" for completion callback.

Check Job Status

GET /v1/tts/jobs/{job_id}
{
  "id": "uuid",
  "status": "pending" | "processing" | "completed" | "failed",
  "audio_url": "...",      // when completed
  "error": "...",          // when failed
  "created_at": "..."
}

Account

Get Balance

GET /v1/account/balance
{ "balance_cents": 450, "total_spent_cents": 50 }

Usage History

GET /v1/account/usage?days=30&model=standard&limit=100

Buy Credits

POST /v1/account/credits
{ "amount_cents": 2000 }

Returns a Stripe checkout URL. Tiers: $5 (0%), $20 (+10%), $50 (+15%), $100 (+20% bonus).

Errors

All errors follow a consistent format:

{ "error": { "code": "error_code", "message": "Human-readable message" } }
HTTPCodeMeaning
400invalid_requestBad parameters
401invalid_api_keyMissing or invalid key
402insufficient_balanceNot enough credits
404not_foundResource not found
429rate_limit_exceeded10/min (free) or 60/min (paid)
500server_errorInternal error