Hướng dẫn tích hợp SnapVoice API
Mọi thứ bạn cần để tích hợp text-to-speech, speech-to-text và voice cloning của SnapVoice vào sản phẩm — xác thực, endpoint, ví dụ code và xử lý lỗi.
Giới thiệu
SnapVoice API là REST API tạo giọng nói đa ngôn ngữ, chuyển giọng nói thành văn bản và nhân bản giọng. Danh mục model/voice được đồng bộ trực tiếp từ hệ thống TTS AI; kết quả tổng hợp trả về audio WAV hoặc MP3, hoặc stream PCM theo thời gian thực.
Base URL
https://api.snapvoice.aiXác thực
Endpoint tạo audio, nhân bản giọng, history và tài khoản cần header xi-api-key. Danh mục model, voice và audio preview được đọc công khai.
Gửi key trong header của mỗi request:
Quyền tối thiểu: tạo audio cần text_to_speech = access; chuyển giọng nói thành văn bản cần speech_to_text = access; enroll/sửa/xóa giọng clone cần voices = read_write, xem giọng đã enroll cần voices = read (hoặc read_write); đọc lịch sử cần history = read (hoặc read_write), xóa lịch sử cần history = read_write; đọc tài khoản cần user = read. Key hợp lệ nhưng thiếu quyền trả 403.
xi-api-key: $SNAPVOICE_API_KEYKhông để lộ API key ở phía trình duyệt. Key chỉ nên dùng ở server.
Tạo API keyBắt đầu nhanh
Lấy provider voice ID từ /v1/tts/voices, sau đó gọi text-to-speech với voice_id, model_id và văn bản để nhận WAV.
# Create a key at https://snapvoice.ai/app/api-keys with Text to Speech = Access.
# Set SNAPVOICE_API_KEY on your server before running this example.
export VOICE_ID="vi_02"
curl --fail-with-body "https://api.snapvoice.ai/v1/tts/voices?model=silverai%2Fsilver-tts-pro&language=vi"
curl --fail-with-body --max-time 330 -X POST "https://api.snapvoice.ai/v1/text-to-speech/$VOICE_ID" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Xin chào từ SnapVoice",
"model_id": "silverai/silver-tts-pro"
}' \
--output speech.wavNhân bản giọng (voice cloning)
Enroll một giọng từ đoạn audio mẫu một lần, sau đó dùng enrollment_id làm voice_id cho text-to-speech bao nhiêu lần cũng được. Toàn bộ luồng chỉ cần API key, không cần đăng nhập.
- Tạo API key với Voices = Read & Write và Text to Speech = Access.
- POST /v1/voice-enrollments với { name, reference_audio, consent: true } (reference_text, model_id, remove_background_noise tùy chọn). Response trả về data.enrollment_id, status "ready" là dùng được ngay.
- POST /v1/text-to-speech/{enrollment_id} với { text, model_id? } để nhận WAV bằng giọng đã clone.
- Quản lý giọng bằng GET /v1/voice-enrollments, PATCH hoặc DELETE /v1/voice-enrollments/{enrollment_id}.
reference_audio là base64 của file WAV PCM 16-bit (mọi sample rate, mono hoặc stereo; có thể kèm tiền tố data:audio/wav;base64,) hoặc PCM thô 24 kHz mono 16-bit. Độ dài 1–22 giây, nên là giọng nói rõ, một người, không nhạc nền. reference_text (transcript) tối đa 500 ký tự; bỏ trống thì hệ thống tự nhận dạng. Tối đa 20 lần enroll mỗi giờ cho mỗi tài khoản.
Enroll không trừ credits. Tổng hợp bằng giọng đã enroll tính 1.5 credit/ký tự (làm tròn lên) cho cả Pro và Flash; synthesis lỗi sẽ được hoàn credits. enrollment_id chỉ dùng được với API key của chính tài khoản sở hữu giọng.
Chỉ nhân bản giọng của chính bạn hoặc giọng bạn đã được chủ sở hữu cho phép. Request enroll bắt buộc gửi consent: true.
# Requires a key with Voices = Read & Write and Text to Speech = Access.
# 1) Enroll a voice from a 1–22 second, 16-bit PCM WAV clip.
# reference_text (transcript) is optional; jq builds the JSON body.
base64 < reference.wav | tr -d '\n' > reference.b64
jq -n --rawfile audio reference.b64 \
'{name: "My voice", reference_audio: $audio, consent: true}' > body.json
curl --fail-with-body --max-time 330 -X POST "https://api.snapvoice.ai/v1/voice-enrollments" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-H "Content-Type: application/json" \
-d @body.json > enrollment.json
# 2) Use data.enrollment_id as the voice_id.
export VOICE_ID=$(jq -r '.data.enrollment_id' enrollment.json)
curl --fail-with-body --max-time 330 -X POST "https://api.snapvoice.ai/v1/text-to-speech/$VOICE_ID" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Xin chào, đây là giọng nói của tôi.","model_id":"silverai/silver-tts-pro"}' \
--output cloned.wavChuyển giọng nói thành văn bản (speech to text)
Gửi file audio dạng multipart tới POST /v1/speech-to-text (trường file, và language nếu muốn) để nhận { text, language_code, duration_seconds, credit_cost }. Hỗ trợ 30 ngôn ngữ; bỏ trống language để tự nhận diện. Mã ngôn ngữ lấy từ GET /v1/speech-to-text/languages.
Chấp nhận WAV, MP3, M4A, OGG, FLAC và WebM, tối đa 25 MB và 10 phút mỗi file. Key cần quyền Speech to Text = Access.
Tính credits theo mỗi giây audio, làm tròn lên. Đơn giá hiện tại nằm ở trường credits_per_second của GET /v1/speech-to-text/languages. Request lỗi được hoàn credits. Văn bản được lưu vào lịch sử (GET /v1/speech-to-text/transcriptions, cần quyền history); file audio không được lưu.
# Requires a key with Speech to Text = Access.
# Omit language to auto-detect; codes come from /v1/speech-to-text/languages.
curl --fail-with-body --max-time 330 -X POST "https://api.snapvoice.ai/v1/speech-to-text" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-F "[email protected]" \
-F "language=vi" > transcript.json
jq -r '.text' transcript.json > transcript.txtDanh sách endpoint
Tất cả endpoint nằm dưới tiền tố /v1. Endpoint cần xác thực được đánh dấu xi-api-key.
Dùng /v1/tts/models và /v1/tts/voices để lấy model_id và voice_id cho tổng hợp. /v1/models và /v1/voices là danh mục metadata cũ; UUID và settings ở đó không dùng cho API tổng hợp hiện tại. Preview dùng chung giữa các model và có thể là WAV hoặc MP3; đọc Content-Type của phản hồi.
| Method | Endpoint | Xác thực | Mô tả |
|---|---|---|---|
| GET | /v1/tts/models | — | List live TTS models from the synthesis provider. |
| GET | /v1/tts/voices | — | List live built-in voices. Filter by model, language, or category. |
| GET | /v1/tts/voices/{voice_id}/preview | — | Read the shared voice preview. Use Content-Type to identify WAV/MP3; supports HEAD and Range requests. |
| POST | /v1/text-to-speech/{voice_id} | xi-api-key text_to_speech: access | Generate speech from text. voice_id is a built-in voice ID (e.g. vi_02) or the enrollment_id of your enrolled voice. Returns audio/wav by default; add ?output_format=mp3 for audio/mpeg (about 10x smaller). |
| POST | /v1/text-to-speech/{voice_id}/stream | xi-api-key text_to_speech: access | Stream speech while it is generated. voice_id is a built-in voice or your enrollment_id (charged at the 1.5x clone rate). Returns raw PCM (audio/pcm, mono s16le); the sample rate is in X-Audio-Sample-Rate. Audio starts in about a second instead of after the whole clip. |
| GET | /v1/speech-to-text/languages | — | List the languages speech-to-text accepts (ISO 639-1 codes, plus yue and tl). |
| POST | /v1/speech-to-text | xi-api-key speech_to_text: access | Transcribe an audio file (multipart: file, language?). Omit language to auto-detect. Up to 25 MB and 10 minutes; billed per started second of audio. |
| GET | /v1/speech-to-text/transcriptions | xi-api-key history: read or read_write | List your transcription history, newest first (?page, ?page_size up to 100). Transcripts only; uploaded audio is not stored. |
| GET | /v1/speech-to-text/transcriptions/{transcription_id} | xi-api-key history: read or read_write | Read one stored transcription. |
| DELETE | /v1/speech-to-text/transcriptions/{transcription_id} | xi-api-key history: read_write | Delete a stored transcription. |
| POST | /v1/voice-enrollments | xi-api-key voices: read_write | Enroll (clone) a reusable voice from a 1–22 s reference clip. Body: { name, reference_audio, consent: true, reference_text?, model_id?, remove_background_noise?, description?, language?, labels? }. Returns 201 with enrollment_id; status "ready" means it can be used for synthesis. |
| GET | /v1/voice-enrollments | xi-api-key voices: read or read_write | List your enrolled voices: { voices: [...] }. |
| GET | /v1/voice-enrollments/{enrollment_id} | xi-api-key voices: read or read_write | Read one of your enrolled voices, including status and a signed preview_url. |
| GET | /v1/voice-enrollments/{enrollment_id}/preview | xi-api-key voices: read or read_write | Get a temporary signed preview_url for your enrolled voice. |
| PATCH | /v1/voice-enrollments/{enrollment_id} | xi-api-key voices: read_write | Update your enrolled voice's name, description, or labels. |
| DELETE | /v1/voice-enrollments/{enrollment_id} | xi-api-key voices: read_write | Delete (archive) your enrolled voice. It can no longer be used for synthesis. |
| GET | /v1/history | xi-api-key history: read or read_write | List generation history. Query: page (default 1), page_size (default 20, max 100). |
| GET | /v1/history/{history_item_id} | xi-api-key history: read or read_write | Read one of your generations, including audio_url (null when audio is missing or expired). |
| DELETE | /v1/history/{history_item_id} | xi-api-key history: read_write | Delete one of your generation history items and its stored audio. |
| GET | /v1/user | xi-api-key user: read | Read your user ID and subscription summary. |
| GET | /v1/user/subscription | xi-api-key user: read | Get your character quota and usage. |
| GET | /v1/user/credit-history | xi-api-key user: read | Read credit transactions. Query: limit (default 100, range 1–1000). |
/v1/tts/modelsList live TTS models from the synthesis provider.
Request
curl https://api.snapvoice.ai/v1/tts/modelsResponse
{
"object": "list",
"data": [
{
"id": "silverai/silver-tts-pro",
"tasks": ["basic", "voice_clone", "voice_design"],
"sample_rate": 24000,
"voice_count": 19,
"voices_url": "/v1/tts/voices?model=silverai/silver-tts-pro",
"voices": [
{
"id": "vi_02",
"name": "Ngọc Hân",
"language": "vi",
"category": "conversational",
"model": "silverai/silver-tts-pro",
"preview_url": "/v1/tts/voices/vi_02/preview"
}
]
}
]
}/v1/tts/voicesList live built-in voices. Filter by model, language, or category.
Request
curl "https://api.snapvoice.ai/v1/tts/voices?model=silverai/silver-tts-pro&language=vi"Response
{
"object": "list",
"data": [
{
"id": "vi_02",
"name": "Ngọc Hân",
"language": "vi",
"category": "conversational",
"use_cases": ["chatbot", "virtual_assistant", "customer_service", "dialogue"],
"model": "silverai/silver-tts-pro",
"sample_rate": 24000,
"preview_url": "/v1/tts/voices/vi_02/preview"
}
]
}/v1/tts/voices/{voice_id}/previewRead the shared voice preview. Use Content-Type to identify WAV/MP3; supports HEAD and Range requests.
Request
curl --fail-with-body "https://api.snapvoice.ai/v1/tts/voices/vi_02/preview" --output preview.audioResponse
# Binary audio; current previews may be audio/x-wav.
# HEAD returns headers without audio; a valid Range request returns 206.
# An unsatisfiable Range returns 416; an unknown preview returns 404./v1/text-to-speech/{voice_id}Generate speech from text. voice_id is a built-in voice ID (e.g. vi_02) or the enrollment_id of your enrolled voice. Returns audio/wav by default; add ?output_format=mp3 for audio/mpeg (about 10x smaller).
Request
curl --fail-with-body --max-time 330 -X POST "https://api.snapvoice.ai/v1/text-to-speech/vi_02" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Xin chào từ SnapVoice","model_id":"silverai/silver-tts-pro"}' \
--output speech.wavResponse
# Binary audio/wav (mono 16-bit) is written to speech.wav.
# For MP3, POST to ".../vi_02?output_format=mp3" and save speech.mp3
# (mp3_44100_128 style values are accepted and map to mp3).
# Model IDs come from /v1/tts/models; current models return 24 kHz.
# On error a JSON body is returned instead:
{ "status": "error", "message": "Insufficient credits", "data": null }
# Insufficient credits returns HTTP 402, not 429.
# X-History-Item-Id correlates the audio with generation history./v1/text-to-speech/{voice_id}/streamStream speech while it is generated. voice_id is a built-in voice or your enrollment_id (charged at the 1.5x clone rate). Returns raw PCM (audio/pcm, mono s16le); the sample rate is in X-Audio-Sample-Rate. Audio starts in about a second instead of after the whole clip.
Request
curl --fail-with-body --no-buffer --max-time 330 -X POST "https://api.snapvoice.ai/v1/text-to-speech/vi_02/stream" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Xin chào từ SnapVoice","model_id":"silverai/silver-tts-flash"}' \
| ffplay -f s16le -ar 24000 -ch_layout mono -nodisp -autoexit -Response
# Raw PCM chunks (mono, 16-bit little-endian) arrive as they are generated.
# Headers: X-Audio-Sample-Rate: 24000, X-Audio-Channels: 1,
# X-Audio-Sample-Format: s16le, X-History-Item-Id: <id>
# Only output_format=pcm (or pcm_24000) is accepted.
# Credits are charged like a normal request. If the upstream fails mid-stream
# the connection is reset and the credits are refunded./v1/speech-to-text/languagesList the languages speech-to-text accepts (ISO 639-1 codes, plus yue and tl).
Request
curl https://api.snapvoice.ai/v1/speech-to-text/languagesResponse
{
"object": "list",
"data": [
{ "code": "vi", "name": "Vietnamese" },
{ "code": "en", "name": "English" }
],
"credits_per_second": 10,
"max_duration_seconds": 600,
"max_file_bytes": 26214400
}/v1/speech-to-textTranscribe an audio file (multipart: file, language?). Omit language to auto-detect. Up to 25 MB and 10 minutes; billed per started second of audio.
Request
curl --fail-with-body --max-time 330 -X POST "https://api.snapvoice.ai/v1/speech-to-text" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-F "[email protected]" \
-F "language=vi"Response
{
"transcription_id": "8d1f0c3a-5b7e-4f2a-9c61-2e4b7a9d0f13",
"text": "Xin chào, hôm nay bạn thế nào?",
"language_code": "vi",
"duration_seconds": 3.2,
"credit_cost": 40
}
# language_code is null when auto-detected. Accepts WAV, MP3, M4A, OGG,
# FLAC and WebM. Too long or unreadable audio returns 400, too large 413,
# insufficient credits 402./v1/voice-enrollmentsEnroll (clone) a reusable voice from a 1–22 s reference clip. Body: { name, reference_audio, consent: true, reference_text?, model_id?, remove_background_noise?, description?, language?, labels? }. Returns 201 with enrollment_id; status "ready" means it can be used for synthesis.
Request
# Build the JSON body from reference.wav (requires jq).
base64 < reference.wav | tr -d '\n' > reference.b64
jq -n --rawfile audio reference.b64 \
'{name: "My voice", reference_audio: $audio, consent: true}' > body.json
curl --fail-with-body --max-time 330 -X POST "https://api.snapvoice.ai/v1/voice-enrollments" \
-H "xi-api-key: $SNAPVOICE_API_KEY" \
-H "Content-Type: application/json" \
-d @body.jsonResponse
{
"status": "success",
"message": "Voice enrolled",
"data": {
"enrollment_id": "3f6b1c2e-8d4a-4b7e-9c1f-2a5d6e7f8a90",
"name": "My voice",
"language": "vi",
"status": "ready",
"reference_audio_duration_sec": 8.4,
"reference_text": "Transcript of reference.wav (optional)",
"remove_background_noise": false,
"preview_url": "https://…signed-url…/preview.wav",
"created_at": "2026-10-15T05:00:00.000Z"
}
}
# reference_audio: base64 of a 16-bit PCM WAV file (any sample rate,
# mono or stereo) or raw 24 kHz mono 16-bit PCM. 1–22 seconds./v1/historyList generation history. Query: page (default 1), page_size (default 20, max 100).
Request
curl "https://api.snapvoice.ai/v1/history?page=1&page_size=20" \
-H "xi-api-key: $SNAPVOICE_API_KEY"Response
{
"status": "success",
"message": "OK",
"data": {
"history": [],
"pagination": {
"page": 1,
"page_size": 20,
"total": 0,
"total_pages": 1
}
}
}/v1/user/subscriptionGet your character quota and usage.
Request
curl https://api.snapvoice.ai/v1/user/subscription \
-H "xi-api-key: $SNAPVOICE_API_KEY"Response
{
"status": "success",
"message": "OK",
"data": {
"tier": "free",
"character_count": 1280,
"character_limit": 10000,
"extra_credits": 0,
"credits_remaining": 8720
}
}Model và giọng
Chọn model_id và voice_id từ danh mục của model đó. Một voice_id có thể xuất hiện ở cả Pro và Flash; bỏ model_id sẽ mặc định dùng Pro.
| Tham số | Kiểu | Khoảng | Mô tả |
|---|---|---|---|
| voice_id | path | GET /v1/tts/voices · GET /v1/voice-enrollments | Built-in voice ID from GET /v1/tts/voices (for example vi_02), or the enrollment_id of one of your enrolled voices. |
| model_id | string | GET /v1/tts/models | Explicit model ID: silverai/silver-tts-pro or silverai/silver-tts-flash. Defaults to silverai/silver-tts-pro when omitted. |
| text | string | 1–3000 chars | Leading/trailing whitespace is trimmed. The 3000 limit and 1 credit per character use JavaScript UTF-16 length (some emoji count as 2). |
API phiên đăng nhập và voice cloning
Các endpoint dưới đây dùng Firebase ID token của người dùng đã đăng nhập (dashboard). xi-api-key không được chấp nhận thay cho token ở các endpoint này. Tích hợp server-to-server hãy dùng /v1/voice-enrollments và /v1/text-to-speech/{enrollment_id} với API key (xem mục Nhân bản giọng). Clone một lần, dialogue và quản lý API key hiện chỉ có qua phiên đăng nhập. Demo /public/* yêu cầu Turnstile và không phải API tích hợp bằng key.
Authorization: Bearer <Firebase ID token>POST /v1/tts/previewSingle voice: { text, model_id?, voice_id?, output_format? } (wav default, or mp3). Enrolled voice: add voice_source: 'enrolled' and enrollment_id.
POST /v1/tts/cloneOne-shot cloning: { text, model_id?, referenceText, referenceAudio, language? } (language defaults to vi). Raw base64 PCM, 24 kHz mono 16-bit, 1–22 seconds; transcript required, max 500 characters.
POST /v1/tts/streamStreaming single voice: { text, model_id?, voice_id? } or { text, model_id?, voice_source: 'enrolled', enrollment_id }. Raw PCM (mono s16le) with X-Audio-Sample-Rate. Stored in history as WAV once complete.
GET /v1/me/transcriptionsYour speech-to-text history (?page, ?page_size). GET or DELETE /v1/me/transcriptions/{transcription_id} for one item.
POST /v1/tts/transcribeSpeech-to-text: multipart { file, language? }. Same limits, billing and response as POST /v1/speech-to-text.
POST /v1/tts/dialogueDialogue: { model_id?, segments: [{ voice_id?, text }] }. Max 20 segments, 3000 characters each, 5000 total; one model per request.
GET /v1/me/voice-enrollmentsList your reusable cloned voices.
POST /v1/me/voice-enrollmentsEnroll a voice: { name, referenceAudio, consent: true, model_id?, referenceText?, removeBackgroundNoise? }. Transcript is optional; noise removal defaults to false.
PATCH /v1/me/voice-enrollments/{enrollment_id}Update your enrolled voice's name, description, or labels.
DELETE /v1/me/voice-enrollments/{enrollment_id}Archive your enrolled voice.
GET /v1/me/voice-enrollments/{enrollment_id}/previewGet a signed preview_url for your enrolled voice.
GET /v1/api-keysList your API keys; raw keys are never returned here.
POST /v1/api-keysCreate a key: { name, scopes }. The raw key is returned once.
PATCH /v1/api-keys/{id}Update your key's name, scopes, or revoked state.
DELETE /v1/api-keys/{id}Revoke your key.
Giới hạn text sau trim: 3000 đơn vị UTF-16. Giọng có sẵn, clone một lần và dialogue: 1 credit/đơn vị. Tổng hợp giọng clone đã lưu: 1.5 credit/đơn vị cho cả Pro và Flash, làm tròn lên. Synthesis lỗi sẽ yêu cầu hoàn credits. Audio và lịch sử có thời hạn lưu riêng; audio_url có thể là null hoặc URL ký tạm thời.
Xử lý lỗi
Lỗi từ backend có dạng { status: "error", message, data: null }. Proxy hoặc Cloudflare có thể trả văn bản/HTML; luôn kiểm tra HTTP status trước khi lưu body thành audio.
Synthesis có timeout upstream 300 giây; ví dụ dùng timeout client 330 giây. Khi nhận 429, chờ theo Retry-After; lỗi 502/503/504 có thể thử lại với backoff. Request không có cơ chế idempotency: nếu mất kết nối sau khi server đã xử lý, gửi lại có thể tạo audio và trừ credits lần nữa; kiểm tra lịch sử trước khi thử lại.
| Mã | Ý nghĩa |
|---|---|
| 400 | Bad request — missing or invalid parameters (e.g. empty text). |
| 401 | Missing or invalid xi-api-key. |
| 402 | Insufficient credits — check credits_remaining or purchase credits. |
| 403 | Forbidden — the key cannot access this resource. |
| 404 | Resource not found (e.g. unknown preview, history item, or enrollment_id that is not yours). Unknown built-in synthesis voices return 400. |
| 413 | Request body exceeds the 25 MB JSON limit. |
| 416 | Voice preview byte range is not satisfiable. |
| 422 | The synthesis provider could not validate the request. |
| 429 | Rate limit hit — respect Retry-After. The app allows 120 requests/minute per IP and 20 voice enrollments/hour per account; provider limits may also apply. |
| 500 | Internal server error. |
| 502 | Upstream request/synthesis failed. Failed synthesis triggers a credit refund. |
| 503 | The TTS model is not ready or the provider is unavailable. |
| 504 | The synthesis provider timed out. |