Tài liệu API

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

base url
https://api.snapvoice.ai

Xá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.

header
xi-api-key: $SNAPVOICE_API_KEY

Không để lộ API key ở phía trình duyệt. Key chỉ nên dùng ở server.

Tạo API key

Bắ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.

cURL
# 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.wav

Nhâ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.

  1. Tạo API key với Voices = Read & Write và Text to Speech = Access.
  2. 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.
  3. POST /v1/text-to-speech/{enrollment_id} với { text, model_id? } để nhận WAV bằng giọng đã clone.
  4. 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.

cURL
# 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.wav

Chuyể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.

cURL
# 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.txt

Danh 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.

MethodEndpoint
GET/v1/tts/models
GET/v1/tts/voices
GET/v1/tts/voices/{voice_id}/preview
POST/v1/text-to-speech/{voice_id}
POST/v1/text-to-speech/{voice_id}/stream
GET/v1/speech-to-text/languages
POST/v1/speech-to-text
GET/v1/speech-to-text/transcriptions
GET/v1/speech-to-text/transcriptions/{transcription_id}
DELETE/v1/speech-to-text/transcriptions/{transcription_id}
POST/v1/voice-enrollments
GET/v1/voice-enrollments
GET/v1/voice-enrollments/{enrollment_id}
GET/v1/voice-enrollments/{enrollment_id}/preview
PATCH/v1/voice-enrollments/{enrollment_id}
DELETE/v1/voice-enrollments/{enrollment_id}
GET/v1/history
GET/v1/history/{history_item_id}
DELETE/v1/history/{history_item_id}
GET/v1/user
GET/v1/user/subscription
GET/v1/user/credit-history
GET/v1/tts/models

List live TTS models from the synthesis provider.

Request

request
curl https://api.snapvoice.ai/v1/tts/models

Response

response
{
  "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"
        }
      ]
    }
  ]
}
GET/v1/tts/voices

List live built-in voices. Filter by model, language, or category.

Request

request
curl "https://api.snapvoice.ai/v1/tts/voices?model=silverai/silver-tts-pro&language=vi"

Response

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"
    }
  ]
}
GET/v1/tts/voices/{voice_id}/preview

Read the shared voice preview. Use Content-Type to identify WAV/MP3; supports HEAD and Range requests.

Request

request
curl --fail-with-body "https://api.snapvoice.ai/v1/tts/voices/vi_02/preview" --output preview.audio

Response

response
# 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.
POST/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

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.wav

Response

response
# 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.
POST/v1/text-to-speech/{voice_id}/stream

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.

Request

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

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.
GET/v1/speech-to-text/languages

List the languages speech-to-text accepts (ISO 639-1 codes, plus yue and tl).

Request

request
curl https://api.snapvoice.ai/v1/speech-to-text/languages

Response

response
{
  "object": "list",
  "data": [
    { "code": "vi", "name": "Vietnamese" },
    { "code": "en", "name": "English" }
  ],
  "credits_per_second": 10,
  "max_duration_seconds": 600,
  "max_file_bytes": 26214400
}
POST/v1/speech-to-text

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.

Request

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

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.
POST/v1/voice-enrollments

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.

Request

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.json

Response

response
{
  "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.
GET/v1/history

List generation history. Query: page (default 1), page_size (default 20, max 100).

Request

request
curl "https://api.snapvoice.ai/v1/history?page=1&page_size=20" \
  -H "xi-api-key: $SNAPVOICE_API_KEY"

Response

response
{
  "status": "success",
  "message": "OK",
  "data": {
    "history": [],
    "pagination": {
      "page": 1,
      "page_size": 20,
      "total": 0,
      "total_pages": 1
    }
  }
}
GET/v1/user/subscription

Get your character quota and usage.

Request

request
curl https://api.snapvoice.ai/v1/user/subscription \
  -H "xi-api-key: $SNAPVOICE_API_KEY"

Response

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ốKhoảng
voice_idGET /v1/tts/voices · GET /v1/voice-enrollments
model_idGET /v1/tts/models
text1–3000 chars

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.

session header
Authorization: Bearer <Firebase ID token>
POST /v1/tts/preview

Single voice: { text, model_id?, voice_id?, output_format? } (wav default, or mp3). Enrolled voice: add voice_source: 'enrolled' and enrollment_id.

POST /v1/tts/clone

One-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/stream

Streaming 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/transcriptions

Your speech-to-text history (?page, ?page_size). GET or DELETE /v1/me/transcriptions/{transcription_id} for one item.

POST /v1/tts/transcribe

Speech-to-text: multipart { file, language? }. Same limits, billing and response as POST /v1/speech-to-text.

POST /v1/tts/dialogue

Dialogue: { model_id?, segments: [{ voice_id?, text }] }. Max 20 segments, 3000 characters each, 5000 total; one model per request.

GET /v1/me/voice-enrollments

List your reusable cloned voices.

POST /v1/me/voice-enrollments

Enroll 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}/preview

Get a signed preview_url for your enrolled voice.

GET /v1/api-keys

List your API keys; raw keys are never returned here.

POST /v1/api-keys

Create 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
400Bad request — missing or invalid parameters (e.g. empty text).
401Missing or invalid xi-api-key.
402Insufficient credits — check credits_remaining or purchase credits.
403Forbidden — the key cannot access this resource.
404Resource not found (e.g. unknown preview, history item, or enrollment_id that is not yours). Unknown built-in synthesis voices return 400.
413Request body exceeds the 25 MB JSON limit.
416Voice preview byte range is not satisfiable.
422The synthesis provider could not validate the request.
429Rate 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.
500Internal server error.
502Upstream request/synthesis failed. Failed synthesis triggers a credit refund.
503The TTS model is not ready or the provider is unavailable.
504The synthesis provider timed out.