Quickstart
Three steps, and the third one returns audio. Nothing here needs an SDK.
1. Get an API key
Keys live on the Developer page in the VieNeu web app. Create one, copy it once — the plaintext is shown at creation and never again — and put it in your environment:
export VIENEU_API_KEY="vn_sk_..."
A key can only be issued against an active token grant, so a brand-new
account has to start one first; the Developer page offers a free 7-day trial that
does exactly that, once per account. Without a grant, key creation answers 403
with No active API token grant found.
Keys beginning vn_sk_ are live. vn_test_ keys behave identically — same
billing, same limits, same endpoints — except that each request is capped at 100
words, which makes them safe to paste into a sample repository.
2. Pick a voice
The catalogue is public — this call needs no key:
curl -s "https://api.vieneu.io/api/v1/voices?engine=v4" | head -c 400
{"voices":[{"id":"Ngọc Lan","description":"Giọng nữ, giọng trầm dịu dàng",
"name":"Ngọc Lan","gender":"female","region":"south","engine":"v4",
"kind":"catalog"}, …]}
The id field is what you send. Always filter by engine. A voice belongs to
one engine, the two catalogues are only partly interchangeable, and sending an id
from the wrong one is a 400 rather than a substitution — see
voice ids differ by engine.
3. Synthesize
POST /v1/audio/speech returns the audio bytes in the response — no job, no
polling. It is OpenAI's endpoint shape, so an OpenAI client works against it
unchanged; see OpenAI-compatible endpoint.
curl
curl https://api.vieneu.io/api/v1/audio/speech \
-H "Authorization: Bearer $VIENEU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "input": "Xin chào, đây là VieNeu.", "voice": "Ngọc Lan" }' \
--output speech.mp3
Python
# pip install requests
import os
import requests
resp = requests.post(
"https://api.vieneu.io/api/v1/audio/speech",
headers={"Authorization": f"Bearer {os.environ['VIENEU_API_KEY']}"},
json={"input": "Xin chào, đây là VieNeu.", "voice": "Ngọc Lan"},
timeout=120,
)
resp.raise_for_status()
with open("speech.mp3", "wb") as f:
f.write(resp.content)
print("wrote speech.mp3", len(resp.content), "bytes")
JavaScript
// Node 18+ — no dependencies.
import { writeFile } from 'node:fs/promises';
const resp = await fetch('https://api.vieneu.io/api/v1/audio/speech', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.VIENEU_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ input: 'Xin chào, đây là VieNeu.', voice: 'Ngọc Lan' }),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${await resp.text()}`);
await writeFile('speech.mp3', Buffer.from(await resp.arrayBuffer()));
console.log('wrote speech.mp3');
You now have an mp3. response_format changes that — wav, opus, pcm and
8 kHz ulaw are all available, with the field-level detail in the
API reference under createSpeech.
Where to go next
- Long text —
/v1/audio/speechholds the connection open for the whole synthesis. Past a few paragraphs, submit a job instead: see the two ways to synthesize. - Playback before the text finishes — Streaming.
- When a call fails — Errors lists every machine-readable
codeand what to do about it. - Everything else — the API reference is generated from the server's own route definitions and covers every field of every endpoint.