API Reference

OpenAI-compatible text-to-speech at a flat monthly fee. Change one URL, keep your code.

Quickstart

The fastest way to hear something come out of VoicePep is one curl. Grab an API key at voicepep.com/#pricing, then:

curl https://api.voicepep.com/v1/audio/speech \
  -H "Authorization: Bearer vp_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "standard",
    "voice": "am_michael",
    "input": "The morning fog lifted off Lake Pepin."
  }' \
  --output hello.mp3

Play hello.mp3. That's the whole product.

Authentication

Every request needs an API key in the Authorization header:

Authorization: Bearer vp_live_your_key

Your key arrives by email after you sign up on a paid tier, or by request at [email protected] for a free tier key. Keys are 32-character hex strings prefixed with vp_live_. Don't commit them to Git.

Swap from OpenAI in one line

If your code already calls OpenAI's /v1/audio/speech endpoint, change one URL and your existing client works:

from openai import OpenAI

client = OpenAI(
    api_key="vp_live_your_key",
    base_url="https://api.voicepep.com/v1",  # <-- one line changed
)

resp = client.audio.speech.create(
    model="standard",           # production renderer today
    voice="am_michael",
    input="Hello from VoicePep.",
)
resp.stream_to_file("out.mp3")
import OpenAI from "openai";
import fs from "fs";

const client = new OpenAI({
  apiKey: "vp_live_your_key",
  baseURL: "https://api.voicepep.com/v1", // <-- one line changed
});

const mp3 = await client.audio.speech.create({
  model: "standard",           // production renderer today
  voice: "am_michael",
  input: "Hello from VoicePep.",
});
const buf = Buffer.from(await mp3.arrayBuffer());
fs.writeFileSync("out.mp3", buf);
Same request/response shape as OpenAI's /v1/audio/speech. Every OpenAI-compatible client library that lets you set base_url works — Python, Node, Ruby, Go, PHP, Java, curl, all of them.

POST /v1/audio/speech

Turn text into an audio file.

Request body

ParameterTypeRequiredDescription
model string yes "standard". Studio/custom rendering is temporarily paused while the GPU lane comes online.
voice string yes Voice ID from the voice list. Twelve curated voices are live today.
input string yes Text to speak. Max 4,096 characters per request. Longer? Send multiple requests and stitch.
response_format string no One of "mp3" (default), "opus", "aac", "wav", "pcm". Same shape as OpenAI.
speed number no 0.5 to 2.0, default 1.0. Values above 1.25 can degrade quality; for most production use, keep this near 1.0.

Response

Binary audio bytes in the requested format. Content-Type reflects the format (audio/mpeg for mp3, audio/wav for wav, etc.).

Example — full curl

curl -X POST https://api.voicepep.com/v1/audio/speech \
  -H "Authorization: Bearer vp_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "standard",
    "voice": "bm_george",
    "input": "Standard voice rendering, one line of code.",
    "response_format": "mp3",
    "speed": 1.0
  }' \
  --output voicepep.mp3

GET /v1/quota

Check your usage this month.

curl https://api.voicepep.com/v1/quota \
  -H "Authorization: Bearer vp_live_your_key"

Returns:

{
  "ok": true,
  "valid": true,
  "tier": "walk",
  "monthly_limit": 100000,
  "used_this_month": 12384,
  "remaining_this_month": 87616,
  "resets_at": "2026-08-01T00:00:00Z"
}

POST /v1/checkout

Get a Stripe checkout URL for a paid tier. Used by the pricing page but you can call it too — useful if you want your own signup UI.

curl -X POST https://api.voicepep.com/v1/checkout \
  -H "Content-Type: application/json" \
  -d '{
    "price_id": "price_0TppiGeGMDltLdCvDaBIJ4Ug"
  }'

Returns:

{
  "ok": true,
  "id": "cs_live_...",
  "url": "https://checkout.stripe.com/c/pay/..."
}

GET /health

Simple liveness probe. Returns HTTP 200 with basic service metadata.

curl https://api.voicepep.com/health

Voice list

Twelve voices ship on every paid tier and work with the production standard model today.

IDNameAccentCharacter
am_michaelMichaelAmericanwarm, dad-narrator
af_sarahSarahAmericanprofessional briefing
bm_lewisLewisBritishgravelly character
bm_georgeGeorgeBritishBBC classical
am_onyxOnyxAmericandeep cinematic
af_bellaBellaAmericanbright
af_heartHeartAmericanwarm storyteller
af_novaNovaAmericancrisp reporter
af_alloyAlloyAmericanneutral smooth
am_adamAdamAmericanyoung casual
am_puckPuckAmericanplayful character
bf_emmaEmmaBritishwarm storyteller

Rendering modes

ModelAvailable onCharacter
standard Free through Enterprise Fast, natural, ideal for automation, phones, and daily narration. All twelve voices.
studio Paused Studio/custom voice rendering is being brought online behind a feature flag. Use standard for production today.

Rate + concurrency limits

Two independent limits per tier: monthly character quota and simultaneous request cap.

TierCharacters / monthConcurrent requests
Free5,0001
Walk ($9)100,0001
Creator ($23)1,000,0002
Agency ($63)5,000,0005
Enterprise ($119)25,000,00010
Elite ($199+)fair-use20 (or dedicated)
Repeatedly hammering past your concurrency cap counts as a signal you need a higher tier. See §3 of the AUP for the "you talk too much" termination clause.

Error responses

All error responses are JSON with an error field.

StatusMeaningBody
400Bad request (missing field, invalid model or voice ID){"error": "missing input"}
401Missing or malformed Authorization header{"error": "missing api key"}
403Invalid API key or terminated account{"error": "invalid api key"}
429Concurrency cap exceeded{"error": "concurrency limit exceeded", "tier": "walk", "max_concurrent": 1, "current": 2}
429Monthly character quota exceeded{"error": "monthly limit exceeded", "tier": "walk", "monthly_limit": 100000, "remaining": 0}
503Studio rendering temporarily paused{"error": "studio voice rendering is temporarily paused"}
500Render engine failure (rare){"error": "render failed"}

Where to go next

Start free →