VoiceWrap

API documentation

Create an API key on the API keys page. Each character costs 1 credit; credits are refunded if audio generation fails.

For AI agents

Three ways to integrate; pick the one your agent supports. Machine-readable: /llms.txt (guide for LLMs) and /api/v1/openapi.json (OpenAPI 3.1).

1. MCP server

URL https://voicewrap.app/api/mcp. Tools: list_voices, text_to_speech, get_job, get_balance. Authenticate with OAuth (sign in, no key needed) or an API key. list_voices and text_to_speech take an optional language field (see Languages).

Claude.ai / Claude Desktop: no API key needed

  1. Settings → Connectors → Add custom connector.
  2. Name it VoiceWrap, paste the URL https://voicewrap.app/api/mcp, click Add.
  3. Click Connect, sign in with Google and choose Allow. Disconnect under API keys & connections.

Other clients use an API key:

Claude Code
claude mcp add --transport http voicewrap https://voicewrap.app/api/mcp \
  --header "Authorization: Bearer sk_live_..."
Cursor · ~/.cursor/mcp.json
{
  "mcpServers": {
    "voicewrap": {
      "url": "https://voicewrap.app/api/mcp",
      "headers": { "Authorization": "Bearer sk_live_..." }
    }
  }
}
Claude Desktop · claude_desktop_config.json
{
  "mcpServers": {
    "voicewrap": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://voicewrap.app/api/mcp",
               "--header", "Authorization: Bearer sk_live_..."]
    }
  }
}

2. OpenAI SDK (change base_url)

Python
from openai import OpenAI

client = OpenAI(api_key="sk_live_...", base_url="https://voicewrap.app/api/v1")
client.audio.speech.create(
    model="voicewrap", voice="Ngọc Huyền", input="Xin chào!"
).write_to_file("speech.mp3")
TypeScript
import OpenAI from "openai";

const client = new OpenAI({ apiKey: "sk_live_...", baseURL: "https://voicewrap.app/api/v1" });
const res = await client.audio.speech.create({ model: "voicewrap", voice: "nova", input: "Xin chào!" });
await fs.promises.writeFile("speech.mp3", Buffer.from(await res.arrayBuffer()));

3. REST API

See the sections below.

Authentication

Authorization: Bearer sk_live_...

Limited to 30 requests per minute per account. Up to 5,000 characters of text per request.

OpenAI compatible: POST /api/v1/audio/speech

Same format as OpenAI. Returns the audio file directly; long text is waited on until it is done (up to about 4.5 minutes). The model field is ignored. The optional language field is a VoiceWrap extension (see Languages).

curl https://voicewrap.app/api/v1/audio/speech \
  -H "Authorization: Bearer $VOICEWRAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": "Xin chào, đây là VoiceWrap.", "voice": "Ngọc Huyền", "response_format": "mp3"}' \
  --output speech.mp3

OpenAI voice names work too. In Vietnamese they map to: alloy → Ngọc Huyền, ash → Minh Triết, ballad → Ngọc Linh, coral → Thùy Dung, echo → Hải Đăng, fable → Thiện Minh, nova → Mai Anh, onyx → Thiền Tâm Đức, sage → Quỳnh Anh, shimmer → Trúc Ly, verse → Thanh Bình. In other languages, each maps to a native voice of the same gender.

Text to speech (jobs): POST /api/v1/tts

Returns a job with an audio link (expires after 1 hour). Up to 500 characters returns right away (200); longer text, or sending "async": true, returns 202, after which you poll GET /api/v1/tts/:id every 2–5 seconds.

curl https://voicewrap.app/api/v1/tts \
  -H "Authorization: Bearer $VOICEWRAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Giá gói Pro là 100.000 đồng.", "voice": "Hải Đăng", "speed": 1.0, "format": "mp3"}'
{
  "id": "f0b2...",
  "status": "succeeded",          // queued | running | succeeded | failed
  "progress": 1,                  // 0..1 while running
  "queue_position": null,         // jobs ahead of this one while queued
  "language": "vi",               // language read; unless sent, the voice's own or detected
  "audio_url": "https://...",     // play, expires after 1 hour
  "download_url": "https://...",  // download the file
  "duration_seconds": 3.4,
  "cost": 28
}

Languages

The API reads 11 languages. Each built-in voice is a native speaker and reads only its own language; your cloned voices read any of them. Send the optional language field (an ISO 639-1 code) on POST /api/v1/tts, on POST /api/v1/audio/speech (a VoiceWrap extension to the OpenAI format) and on the MCP tool text_to_speech. When it is omitted, a built-in voice sets the language; with a cloned voice or no voice, the language is detected from the text, and with no voice that language's default voice (listed below) reads it. Numbers, percentages and currency are spelled out the way each language says them.

Supported codes, with each language's default voice:

Any other code, including one detected from the text, returns 400 unsupported_language. A built-in voice with a different language returns 400 voice_language_mismatch, listing that language's voices.

POST /api/v1/tts
curl https://voicewrap.app/api/v1/tts \
  -H "Authorization: Bearer $VOICEWRAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "こんにちは、VoiceWrap です。", "voice": "Anna", "language": "ja"}'
POST /api/v1/audio/speech
curl https://voicewrap.app/api/v1/audio/speech \
  -H "Authorization: Bearer $VOICEWRAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello from VoiceWrap.", "voice": "nova", "language": "en"}' \
  --output hello.mp3
Python · OpenAI SDK
client.audio.speech.create(
    model="voicewrap", voice="nova", input="Hello from VoiceWrap.",
    extra_body={"language": "en"},  # language is a VoiceWrap extension, so it goes in extra_body
).write_to_file("hello.mp3")

Voices: GET /api/v1/voices

Pass voice as a name (with or without diacritics, e.g. "ngoc-huyen"), an id, or an OpenAI voice name. When omitted, the default voice for the language is used. Add ?language=ja to list only the voices that read that language (plus your cloned ones). Each voice has language (null for cloned voices, which read every language) and gender.

curl "https://voicewrap.app/api/v1/voices?language=vi" -H "Authorization: Bearer $VOICEWRAP_API_KEY"

{ "voices": [ { "id": "...", "name": "Ngọc Huyền", "key": "ngoc-huyen",
                "description": "Nữ · Miền Bắc · Tự nhiên", "type": "system",
                "language": "vi", "gender": "female",
                "preview_url": "https://..." } ] }

Voice cloning: POST /api/v1/voices

3 to 15 seconds of clear speech, plus an exact transcript of it. Only use your own voice or the voice of someone who has consented.

curl https://voicewrap.app/api/v1/voices \
  -H "Authorization: Bearer $VOICEWRAP_API_KEY" \
  -F name="Giọng của tôi" \
  -F ref_text="Nội dung chính xác của đoạn ghi âm" \
  -F consent=true \
  -F file=@sample.wav

Error codes

{ "error": { "code": "insufficient_credits", "message": "..." } }
API documentation · VoiceWrap