Chuyển tới nội dung chính

Changelog

Thay đổi của Cloud API (/api/v1). Mọi mục đánh dấu ⚠️ Thay đổi hành vi đều có thể ảnh hưởng đến tích hợp đang chạy của bạn, kể cả khi bạn không sửa gì.


2026-10-10 — Gói của key không trả được thì các gói khác của bạn trả​

⚠️ Thay đổi hành vi​

Request mà gói của key không trả được thì một gói khác của bạn trả. Mỗi key tính tiền trên một gói. Trước đây, khi gói đó không trả được — còn quá ít token, chạm hạn mức ngày hoặc tuần, hết hạn — request bị từ chối, kể cả khi tài khoản còn một gói khác đang hoạt động và dư dả: gói còn 99 token không bao giờ trả nổi 195 token của một request V4, nên nó không bao giờ "hết", và mọi lời gọi đều bị từ chối ngay cạnh một gói quà 400.000 token. Giờ gói của key vẫn trả trước mỗi khi trả được; khi không, gói cũ nhất trong số các gói còn hoạt động khác của bạn có hỗ trợ engine đó sẽ trả, đúng như trong web app. Mỗi request vẫn do một gói trả, và tiền hoàn luôn về đúng gói đã trả. Không có gì rơi xuống phần miễn phí hằng ngày. Sách nói và MCP server tính tiền theo cùng cách này.

GET /v1/balance theo cùng quy tắc. remaining là chỗ trống nhiều nhất của một gói trả được (không bao giờ là tổng), và plan là gói mà con số đó đo trên — không còn luôn là gói của key.

Key có gói không còn hoạt động giờ nhận được code. Khi gói mà key gắn vào đã dùng hết, hết hạn hoặc đã được thay, và không gói nào khác đang hoạt động trả được, lỗi 403 giờ kèm code: "GRANT_INACTIVE" và required. Trước đây chỉ có câu chữ, không có code. Xem Lỗi.

Bắt đầu sách nói tính mọi gói trả được, theo từng chương. POST /v1/audiobooks/{bookId}/start trước đây chỉ so cuốn sách với gói của key. Mỗi chương do một gói trả trọn, nên giờ nó trả 402 insufficient_tokens khi các gói của bạn cộng lại không đủ cho các chương, hoặc khi có chương tới lượt mà không gói nào trả được — ví dụ hai chương 39.000 token trên ba gói mỗi gói 30.000. Lỗi thứ hai nêu tên chương đó, kèm ước tính của chương là required và số nhiều nhất một gói còn lại lúc đó là remaining.

Mới​

spendableTokens trong GET /v1/balance. Tổng số key tiêu được ngay lúc này, request này nối request kia: mọi gói trả được, mỗi gói tính tới hạn mức ngày và tuần của riêng nó, cộng lại. Con số giảm đúng bằng chi phí mỗi request, dù gói nào trả — remaining thì không còn như vậy khi gói của key trả cạnh một gói lớn hơn. Chỉ một gói thì nó bằng remaining. MCP server hiện con số này sau mỗi lần tạo audio.

plan.isGift trong GET /v1/balance. plan là gói còn nhiều chỗ nhất, nên nó có thể là token VieNeu tặng chứ không phải một gói: gói còn 99 token cạnh 400.000 token được tặng thì plan là phần được tặng. isGift: true cho biết điều đó — token tặng không có hạn mức ngày/tuần và không hết hạn — để client không gọi nó là gói bạn đang dùng. MCP server giờ gọi đúng là token được tặng.


2026-10-02 — Sách nói dài: không mất chữ, không kẹt​

⚠️ Thay đổi hành vi​

Chương dài hơn mức gói tạo được bị từ chối ngay lúc thêm. Mỗi chương được tính tiền trong một lần, nên với gói có hạn mức token theo ngày hoặc tuần, chương tốn nhiều hơn hạn mức không bao giờ bắt đầu được: trước đây nó nằm chờ token mãi. Giờ POST /v1/audiobooks/{bookId}/chapters trả 400 chapter_over_plan_limit kèm chapterCharsMax, và mọi cuốn sách đều báo chapterCharsMax. Gói không có hạn mức như vậy thì giữ nguyên (60.000 ký tự).

Mới​

afterSegment khi nối tiếp một chương. Đi cùng appendTo, truyền số đoạn chương đang có; số khác đi thì nhận 409 segment_mismatch kèm câu chương đang kết thúc, nên request gửi lại không thêm chữ hai lần và request bị mất không để lại lỗ hổng. Không truyền thì request lặp đúng các đoạn cuối của chương nhận 409 duplicate_segments, còn chương mới giống hệt chương vừa thêm nhận 409 duplicate_chapter. Công cụ MCP add_audiobook_chapter nhận after_segment và cho thấy mỗi chương hiện kết thúc thế nào. Xem Sách nói.

Thay đổi​

Chương lỗi tự được tạo lại. Chương có job lỗi — deploy thay máy chủ hai lần trong lúc tạo một chương dài, máy chủ giọng gặp sự cố — vẫn được hoàn token như trước, rồi tự tạo lại sau vài phút, tối đa hai lần, dùng tiếp các phần đã xong. Job đứng yên 45 phút cũng bị đánh lỗi và hoàn token như vậy, nên không còn chặn mọi sách khác. Bước hoàn thiện MP3 thử lại với thời gian chờ tăng dần trong khoảng một giờ rồi mới giao WAV, và bản thu tải về bị thiếu, hay MP3 ngắn hơn bản thu, bị từ chối chứ không được giao.

Đỉnh của MP3 nằm dưới −3 dBTP. Bước hoàn thiện giờ đặt mục tiêu thấp hơn nửa decibel và thêm bộ giới hạn đỉnh trước khi nén MP3, vì bước nén làm đỉnh nhích lên một chút: hai chương của một cuốn sách thử trên prod đã chạm −2,8 dBTP. Độ lớn vẫn giữ ở −19 LUFS.


2026-10-01 — Sách nói, qua API và trong MCP server​

Mới​

Sách nói. Một cuốn sách gồm một giọng dẫn chuyện và tối đa 30 giọng nhân vật đọc các chương viết dưới dạng kịch bản — lời dẫn chuyện, và từng câu thoại kèm nhân vật nói câu đó. POST /v1/audiobooks tạo sách, POST /v1/audiobooks/{bookId}/chapters thêm chương, POST /v1/audiobooks/{bookId}/start đưa vào hàng chờ, GET /v1/audiobooks/{bookId} theo dõi tiến độ kèm link tải của từng chương đã xong. Sách được tạo ở chế độ nền, mỗi lần một chương, vào lúc cụm GPU rảnh, nên mất cỡ vài giờ chứ không phải vài giây. Mỗi chương bị trừ token theo ký tự khi bắt đầu tạo, được hoàn nếu lỗi, được xử lý âm thanh thành MP3 (−19 LUFS, đỉnh ≤ −3 dBTP, khoảng lặng hai đầu, thẻ ID3) và lưu vào Thư viện. Chỉ key LIVE và giọng trong kho. Xem Toàn bộ operation.

Sách nói trong MCP server. Sáu công cụ và một trình phát chương giúp Claude hoặc ChatGPT biến văn bản người dùng đưa thành sách nói nhiều giọng. Xem Sách nói.

"VieNeu làm được gì?" trong MCP server. Công cụ list_capabilities (trong Claude và ChatGPT là một thẻ menu: bấm câu ví dụ để gửi) và năm prompt có sẵn. Tham số tuỳ chọn của các công cụ giờ nhận cả null. Xem MCP server.

Đã kết nối trước bản này? Hãy kết nối lại. App giữ danh sách công cụ lấy từ lúc kết nối, nên công cụ mới chỉ hiện sau khi bạn ngắt kết nối VieNeu rồi kết nối lại. Từ nay serverInfo.version của server đổi mỗi khi công cụ đổi (1.2.0+<dấu vân tay>), cho các app làm mới theo nó. Xem Xử lý sự cố.

Tìm giọng hiểu lời mô tả vai. Trong MCP server, search của list_voices nhận đúng kiểu trợ lý hay viết, "giọng nam trầm ấm miền Bắc": giới tính và vùng miền lấy từ thông tin của giọng, từ có dấu phải khớp đúng dấu, các từ như "giọng" được bỏ qua, và khi không giọng nào có đủ mọi từ thì trả về các giọng gần nhất kèm phần còn thiếu. Xem MCP server.


2026-10-01 — MCP server trả MP3 và có trình phát trong khung chat; X-Vieneu-Job-Id trên /v1/audio/speech​

Mới​

MCP server trả MP3 và phát ngay trong khung chat. Văn bản tới 1.500 ký tự giờ trả về MP3 (nhẹ khoảng 10 lần so với WAV), và trong Claude, ChatGPT kết quả hiện thành trình phát ngay trong cuộc trò chuyện. Xem MCP server.

POST /v1/audio/speech cho biết mã của bản lưu. Response thành công (không stream) có thêm header X-Vieneu-Job-Id: mã mà VieNeu dùng để lưu một bản của audio bạn vừa nhận. Giây lát sau, GET /v1/tts/{jobId} trả completed kèm audioUrl đã ký sẵn cho đúng những byte đó — tiện khi bạn cần link để chia sẻ thay vì file thô. Header này được mở cho trình duyệt đọc qua CORS.

GET /v1/balance. Số token key đang gọi tiêu được ngay lúc này, gói mà nó trừ, và hạn mức ngày/tuần của gói kèm giờ làm mới. Không trừ token. MCP server có cùng thông tin qua công cụ get_token_balance, và báo số token còn lại sau mỗi lần tạo audio xong.

Đăng nhập MCP dùng được với ChatGPT. Máy chủ xác thực giờ nhận metadata document ưu tiên private_key_jwt miễn là nó cũng cho phép none (ChatGPT là vậy), và đăng ký động nhận client_secret_post / client_secret_basic.


2026-09-30 — MCP server chạy sẵn: dùng VieNeu ngay trong Claude và ChatGPT​

Mới​

https://api.vieneu.io/mcp — thêm địa chỉ này vào Claude, ChatGPT, Cursor hoặc Claude Code, đăng nhập tài khoản VieNeu, rồi nhờ đọc tiếng Việt bằng lời thường. Trợ lý tự tìm giọng, tạo audio và trả link tải. Không cần cài gói, không cần dán API key: trợ lý đăng nhập qua OAuth 2.1 và bạn cho phép trên một trang của VieNeu. Mỗi lần gọi công cụ tính phí đúng như lời gọi /v1 tương ứng. Xem MCP server và hướng dẫn cho từng app: Claude, ChatGPT và các app khác.

Danh sách app đã kết nối, và nút gỡ kết nối, nằm ở trang Nhà phát triển.


2026-09-25 — Trúng cache thì POST /v1/tts trả completed ngay​

Mới​

POST /v1/tts trả luôn link audio khi audio đã có sẵn. Yêu cầu giống hệt nhau — cùng text, giọng, tốc độ, cảm xúc và engine, từ bất kỳ tài khoản nào — được phục vụ từ cache nội dung thay vì tổng hợp lại. Trước đây lời gọi như vậy vẫn trả status: "queued" như mọi lời gọi khác, đẩy bạn đi poll một đoạn audio đã có sẵn: mất trọn một chu kỳ poll cho không.

Nay nó trả status: "completed" kèm audioUrl, audioUrlExpiresIn và duration — đúng body mà GET /v1/tts/{jobId} sẽ trả — nên không còn gì để poll. Cách tính phí không đổi (trúng cache vẫn trừ token như trước).

Nếu client của bạn luôn poll sau khi gửi thì không hỏng gì: lần poll trả về cùng body completed. Muốn tận dụng đường tắt, rẽ nhánh theo status ở response gửi:

const job = await submit(text, voiceId);
const done = job.status === 'completed' ? job : await pollUntilDone(job.jobId);

Lời gọi không trúng cache vẫn trả queued — replay theo Idempotency-Key của một lần gửi trước cũng vậy, bất kể job đó đang ở trạng thái nào; hãy poll nó. Thi thoảng file của bản cache vẫn đang trên đường lên kho lưu trữ; khi đó response giữ queued và lần poll sau đó một chút sẽ báo completed.


2026-09-24 — v3 rút khỏi Cloud API​

⚠️ Thay đổi hành vi​

Engine v3 không còn trên /api/v1. Từ 08:00 ngày 2026-09-24 (GMT+7), Cloud API chỉ dựng tiếng bằng v4. Bất kỳ request nào nêu "engine": "v3" — trên POST /v1/tts, /v1/tts/stream, /v1/audio/speech, /v1/dialogue, /v1/dub, /v1/srt và các biến thể multipart của chúng — đều bị từ chối với 400 trước khi bất cứ khoản nào bị tính, và thông báo nói rõ:

Engine "v3" was retired on 2026-09-24. Use engine "v4" and a voice from GET /v1/voices?engine=v4 — the two catalogues share no ids.

Request không nêu engine thì vốn đã rơi vào v4, engine mặc định, nên không bị ảnh hưởng — trừ khi nó mang theo một voice id của v3, là điểm kế tiếp.

Các endpoint danh mục giờ trả gì. GET /v1/engines liệt kê đúng một engine, { "key": "v4", "isDefault": true, "sampleRate": 48000, "billingMultiplier": 3, "features": ["generate", "clone", "dialogue", "stream", "dub", "srt"] }, kèm "globalMultiplier": 1.3 bên cạnh. GET /v1/voices chỉ liệt kê giọng v4, cộng thêm các bản nhân bản v4 của chính bạn khi gửi kèm key; giọng v3, và bản nhân bản đăng ký trên v3, không còn được liệt kê. GET /v1/voices?engine=v3 là 400 với thông báo ở trên. Id của danh mục đã ngừng — phần lớn là slug vieneu-… khó đọc — gần như không chung không gian với tên hiển thị của v4, nên một giọng v3 hard-code sẵn vẫn tiếp tục lỗi ở voiceId kể cả khi bạn đã bỏ engine: hãy lấy một id mới từ GET /v1/voices?engine=v4.

Trên route tương thích OpenAI, "model": "vieneu-v3" trả 400 kèm Model 'vieneu-v3' is retired. Engine "v3" was retired on 2026-09-24. …. tts-1, tts-1-hd, gpt-4o-mini-tts, vieneu và vieneu-v4 đều trỏ về v4. Trường emotion (natural / storytelling) vốn chỉ dành cho v3; nó vẫn được nhận, rồi bị bỏ qua — v4 không có kiểu đọc.

GET /v1/emotion-tags không kèm engine giờ trả lời cho engine mặc định, v4: không có kiểu đọc và ba thẻ biểu cảm đặt trong văn bản, [cười], [thở dài] và [hắng giọng]. Trước đây nó trả bộ của v3. ?engine=v3 là 400. Các endpoint /v1/audio/… tương ứng cũng vậy.

Bản nhân bản đăng ký trên v3 — mọi giọng tạo trước 2026-08-28, thời điểm việc đăng ký chuyển sang v4 — không còn dựng tiếng được qua API, vì engine duy nhất đọc được đoạn mẫu của chúng chính là engine giờ trả 400. Gửi một id như vậy làm voiceId (hay voice của /v1/audio/speech) sẽ nhận 400 kèm code: "CLONE_ENGINE_RETIRED" và engine của giọng, thay vì bị âm thầm dựng trên v4 bằng một chất giọng bạn chưa từng đăng ký. Hãy đăng ký lại giọng trên Studio; id clone_… mới chạy trên POST /v1/tts và POST /v1/tts/stream y như trước.

Những gì không bị ảnh hưởng. Audio đã tạo trên v3 vẫn nguyên — các mục trong thư viện và link tải vẫn hoạt động. Và đây chỉ là thay đổi của Cloud API: bản v3 Turbo chạy tại chỗ trong Python SDK và ứng dụng Windows chạy trên máy của bạn, không đổi gì.


2026-09-23 — Nhân bản giọng chuyển hẳn về Studio web​

⚠️ Thay đổi hành vi​

Các endpoint tạo giọng nhân bản đã đóng. POST /v1/voices, DELETE /v1/voices/{voiceId}, POST /v1/clone, POST /v1/upload và POST /v1/prepare nay trả 410 kèm code: "CLONE_WEB_ONLY" và cloneUrl. Không trừ token, không chạm tới GPU — lỗi từ chối xảy ra trước cả hai việc đó. Hãy tạo giọng tại vieneu.io/#/clone.

Vì sao đưa về web: nhân bản cho ra giọng tốt là việc cần có người dẫn. Studio khử nhiễu clip, chép lời bằng Whisper và cho bạn nghe thử trước khi lưu. Một clip mẫu ồn, chép lời sai hoặc sai độ dài sẽ làm hỏng mọi lần tạo tiếng sau này bằng giọng đó chứ không riêng lần tạo giọng — mà gọi qua API thì không cách nào thấy được điều đó trước khi đã trả phí tạo giọng.

Phần tạo tiếng không đổi gì. Giọng nhân bản trên web vẫn hiện trong GET /v1/voices khi bạn gửi kèm key ("kind": "cloned"), và id clone_… vẫn là một voiceId bình thường ở POST /v1/tts và POST /v1/tts/stream, giá đúng bằng giọng catalogue. Hệ tích hợp nào chỉ DÙNG giọng nhân bản thì không phải sửa gì cả.

Các route nhân bản đã được gỡ khỏi /openapi.json và tài liệu tham chiếu API, nên client sinh tự động sẽ mất chúng ở lần sinh lại kế tiếp. Các code lỗi nhân bản cũ (CLONE_MONTHLY_CAP, CLONE_QUOTA_EXCEEDED, CLONE_REF_*, …) thuộc về các route đó nên không còn tới được một API key nữa; những trần theo gói ấy vẫn áp nguyên trên Studio. Xem Lỗi → Nhân bản giọng.


2026-09 — Body lỗi, code hạn mức, và cổng engine khi tạo giọng nhân bản​

⚠️ Thay đổi hành vi — chỉ thêm vào, không bỏ đi gì​

Đọc dòng này trước đã: không có trường nào bị bỏ, bị đổi tên, hay đổi kiểu dữ liệu lẫn ý nghĩa. Cả ba thay đổi dưới đây chỉ thêm nội dung vào những body vốn đã được gửi. Thứ duy nhất có thể nhận ra khác biệt là một tích hợp từ chối trường lạ — một schema chặt, hay một struct Go giải mã có bật kiểm tra trường không khai báo — và đó chính là lý do mục này được xếp vào thay đổi hành vi thay vì phần Mới.

Mọi body lỗi dạng gốc trên /v1 giờ đều mang statusCode. Trước đây trường này chỉ có ở những body không mang gì khác: ngay khi một lỗi từ chối có thêm code máy đọc được thì nó mất statusCode — tức là đổi lấy một lý do máy đọc được thì mất đi một trường bạn vẫn luôn đọc được. Giờ chỉ còn một dạng duy nhất, trên mọi lỗi mà envelope của nền tảng bao phủ. Dòng status của HTTP vẫn là bản chuẩn. POST /v1/audio/speech không bị ảnh hưởng — route đó trả lời bằng envelope của OpenAI, vốn không có statusCode.

Lỗi hạn mức giờ mang code, kèm resetAt, remaining và required ở những chỗ bước trừ token cung cấp được. Tám chỗ từ chối trên bảy route có tính tiền — /v1/tts, /v1/tts/stream, /v1/dialogue, /v1/dub (hai chỗ: cổng kiểm khả năng chi trả trước khi tốn GPU, và bước trừ tiền sau đó), /v1/clone, /v1/srt và /v1/vapi/speech — trước đây chỉ ném ra một câu trần trụi, nên cách duy nhất để phân biệt "nạp thêm" với "chờ một tiếng" là dò câu chữ tiếng Anh. Giờ chúng mang GRANT_EXPIRED, GRANT_TOKENS_EXHAUSTED, GRANT_DAILY_LIMIT, GRANT_WEEKLY_LIMIT hoặc CONCURRENT_CONFLICT, và hai loại trần tự phục hồi thì kèm resetAt theo chuẩn ISO 8601 nói rõ khi nào hết. message giữ nguyên, nên một client chỉ đọc mỗi trường đó vẫn chạy như cũ. Xem Lỗi để biết từng code nghĩa là gì và phải làm gì.

POST /v1/voices giờ kiểm đúng engine sẽ thực sự chạy. Tạo giọng nhân bản chỉ còn chạy trên v4 từ 2026-08-28, nhưng chốt kiểm ở cửa vào vẫn đang khẳng định những điều về v3 — nên một lượt tạo giọng không ghi engine nào vẫn có thể bị từ chối vì tình trạng của một engine nó không bao giờ dùng tới. Giờ phép kiểm chạy trên đúng engine mà request sẽ dùng để tạo giọng, và chỉ chạy khi bạn ghi rõ engine.

  • Bạn sẽ thấy: một lượt tạo giọng bỏ trống engine — tức đường đi bình thường — không còn hỏng vì những lý do chẳng liên quan gì tới nó.
  • Không có gì đổi: ghi rõ "engine": "v3" thì vẫn bị từ chối với 400 CLONE_ENGINE_NOT_ALLOWED, và ghi rõ một engine mà gói của bạn không có thì vẫn là 403.

2026-09 — Webhooks​

Mới​

Webhooks cho tác vụ bất đồng bộ. Đăng ký một endpoint https bằng POST /v1/webhooks, và thay vì polling GET /v1/tts/{jobId}, bạn nhận tts.job.completed hoặc tts.job.failed ngay khi job kết thúc. Sự kiện mang đủ thông tin để xử lý mà không cần gọi thêm, kèm một URL tải audio có hiệu lực một giờ.

  • Ký bằng HMAC-SHA256 trong header Vieneu-Signature: t=…,v1=… — cùng khuôn với Stripe, nên bộ kiểm chữ ký bạn đã viết dùng lại được gần như nguyên vẹn. Đoạn verifySignature chép-dán-là-chạy có trong Webhooks.
  • Gửi ít nhất một lần và không theo thứ tự. Trùng lặp là chuyện bình thường: hãy khử trùng lặp theo id (ổn định theo từng job + loại sự kiện). Đừng khử trùng lặp theo chữ ký — mỗi lần thử đều được ký lại nên t và v1 đều đổi.
  • Một lần gửi hỏng sẽ được thử lại, tổng cộng tối đa 6 lượt, ở các mốc t+0, +0.5m, +2.0m, +5.5m, +13.0m, +28.5m — tức khoảng 28,5 phút cho cả loạt, và khoảng cách dài nhất giữa hai lần thử là 15,5 phút. (Mục này ban đầu ghi "khoảng 15 phút"; đó là tính nhầm công thức backoff, xem Webhooks.) Hãy đặt mọi ngưỡng đối soát trên 15,5 phút. Hết lượt thử thì sự kiện bị đưa vào dead-letter: không gửi lại nữa, tài khoản của bạn nhận một thông báo, và GET /v1/webhooks/{id}/deliveries cho biết vì sao. Audio không mất — GET /v1/tts/{jobId} vẫn trả về job và một URL tải mới.
  • Endpoint phải là https và phải trỏ tới địa chỉ công khai. Dải IP riêng, loopback, link-local, CGNAT và các dải dành riêng đều bị từ chối — cả lúc đăng ký lẫn tại đúng thời điểm gửi. Mọi phản hồi 3xx bị tính là gửi hỏng.
  • Xoay signing secret bằng POST /v1/webhooks/{id}/rotate-secret. Secret cũ còn hiệu lực 24 giờ và mỗi sự kiện mang một v1= cho mỗi secret còn hiệu lực, nên bạn triển khai secret mới mà không rớt sự kiện nào.

Không có gì thay đổi hành vi: polling vẫn chạy y hệt, và tài khoản chưa đăng ký endpoint nào thì không thấy khác biệt gì.


2026-08 — Định dạng đầu ra, tương thích OpenAI, và Vapi​

Mới​

Giọng nhân bản chạy được trên POST /v1/tts/stream. Truyền id clone_… (lấy từ GET /v1/voices, tạo bằng POST /v1/voices) vào voiceId là stream được, y như một giọng có sẵn. Trước đây đường stream từ chối mọi id clone_… trong khi ứng dụng web đã stream giọng nhân bản từ lâu — worker vốn hỗ trợ, chỉ có bề mặt công khai là chặn.

  • Tính tiền không đổi: vẫn theo số ký tự gửi lên × hệ số của engine. Giọng nhân bản không có phụ phí riêng; khoản duy nhất là phí ghi danh một lần ở POST /v1/voices.
  • Giọng nhân bản gắn với đúng engine lúc ghi danh, nên quy tắc "stream chỉ chạy v4" vẫn áp dụng. Clone mới đều ghi danh v4.
  • Không phải là thay đổi hành vi: những gì chạy được hôm qua vẫn chạy y hệt.

Nhiều định dạng đầu ra. POST /v1/tts/stream và POST /v1/audio/speech giờ nhận mp3, opus, pcm (thô, không header) và ulaw (G.711 8 kHz cho tổng đài), kèm chọn sample rate. Trước đây chỉ có WAV 48 kHz. mp3 nhỏ hơn WAV khoảng 6 lần.

POST /v1/audio/speech là bản drop-in thật sự cho OpenAI. Trỏ SDK OpenAI vào https://api.vieneu.io/api/v1 với API key của bạn là chạy, không sửa gì thêm. speed đã được áp dụng, model chọn engine, và stream_format cho phép nhận audio ngay trong lúc đang tạo (chunked hoặc SSE kiểu OpenAI). Thêm GET /v1/audio/voices để các client OpenAI lấy danh sách giọng.

POST /v1/vapi/speech — webhook custom-voice cho Vapi. Trỏ custom-voice của assistant vào URL này là agent thoại của bạn nói tiếng Việt. Chi tiết trong Tích hợp Vapi.

Header hạn mức trên mọi phản hồi. X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, và X-Request-Id — hãy đưa kèm X-Request-Id khi liên hệ hỗ trợ, đó là id dùng để tra log của chúng tôi.

Tài liệu công khai. Mục Cloud API trên docs.vieneu.io, kèm decoder tham chiếu Python và JavaScript cho streaming.

⚠️ Thay đổi hành vi​

aiRefine mặc định chuyển từ BẬT sang TẮT. Bước tinh chỉnh bằng AI (kiểm duyệt nội dung + chuẩn hoá phát âm cho công thức, từ viết tắt, tiếng Anh xen kẽ) trước đây chạy mặc định trên /v1 và tính thêm phụ phí. Giờ bạn phải chủ động bật bằng "aiRefine": true.

  • Bạn sẽ thấy gì: chi phí mỗi request giảm, độ trễ giảm, và văn bản được đọc đúng như bạn gửi.
  • Nếu bạn muốn giữ hành vi cũ: thêm "aiRefine": true vào request. Với POST /v1/srt (multipart) là trường aiRefine=true.
  • Chuẩn hoá văn bản tất định (cách đọc hoá học, gộp CHỮ HOA, tầng phiên âm sea-g2p) vẫn chạy trong mọi trường hợp — tiếng Việt vẫn đọc đúng.

Mặc định của response_format trên /v1/audio/speech chuyển từ wav sang mp3. Đây là mặc định của OpenAI, và một client OpenAI bỏ trống trường này là đang mong đợi mp3. Nếu bạn cần WAV, gửi "response_format": "wav".

Hạn mức đổi đơn vị: từ mỗi IP sang mỗi API key. Trước đây đếm theo địa chỉ IP, nghĩa là một văn phòng dùng chung mạng phải chia nhau hạn mức, còn một key chạy trên nhiều máy thì được nhân lên. Giờ đếm theo key — đúng thứ bạn mua. Đi kèm, trần của ba route tổng hợp chính đã được nâng lên 300 request/phút để không ai bị hụt so với trước.

Đây là hạn mức của tầng ứng dụng. Đứng trước nó là một proxy biên vẫn đếm theo địa chỉ nguồn, và tầng đó không đổi. Cách phân biệt: 429 có kèm X-RateLimit-* là key của bạn chạm trần ứng dụng; 429/503 trần trụi không mang header nào là proxy biên chặn theo IP — dùng chung với mọi người đứng sau địa chỉ đó. Xem Hạn mức.

Sửa lỗi​

  • Streaming qua api.vieneu.io không còn bị proxy đệm lại — audio đến ngay khi được tạo, đúng như thiết kế.
  • POST /v1/tts/stream giờ báo đúng định dạng và sample rate thật trong header X-Output-Format / X-Sample-Rate, thay vì lặp lại thứ bạn yêu cầu.
  • Stream bị cắt giữa chừng được hoàn tiền đáng tin cậy hơn: một stream kết thúc đúng quy cách nhưng không mang audio nào giờ cũng được hoàn.

Giới hạn đã biết​

stream_format (và streaming nói chung) chỉ nên dùng với pcm và ulaw. Các khung audio được mã hoá độc lập nhau, nên nối mp3 lại sẽ có khoảng lặng ở mỗi mối nối, còn opus trở thành một chuỗi stream Ogg mà phần lớn trình duyệt chỉ phát được stream đầu tiên. Cần một file mp3 hoặc opus hoàn chỉnh thì gửi request thường, không streaming.