Quy chuẩn gọi Video API đầy đủ
Quy chuẩn thống nhất cho API tạo video của 88API.
Trang này là quy chuẩn tạo video thống nhất mà 88API công bố cho khách hàng, áp dụng cho mọi model video do 88API cung cấp. Khách hàng chỉ cần lấy ID model từ danh sách model mà API Key của mình nhìn thấy, rồi dùng giao diện thống nhất trên trang này.
Hiện tại, mọi tác vụ video dùng chung giao thức “lấy model → gửi → truy vấn định kỳ → tải xuống”. Các tài khoản khác nhau có thể thấy ID model khác nhau; thời lượng, tỷ lệ khung hình, độ phân giải và số lượng tư liệu tham chiếu mà mỗi model hỗ trợ cũng có thể khác nhau. Đừng áp khả năng của model này cho model khác.
Cập nhật ngày 2026-10-10. Tham số và ví dụ riêng của từng thương hiệu đã được tách thành các trang độc lập, xem Quy chuẩn theo từng thương hiệu bên dưới. Quy trình khuyến nghị: trước tiên gọi
GET /v1/modelsđể lấy ID model mà Key hiện tại được dùng; tư liệu HTTPS đã có sẵn thì tham chiếu trực tiếp; tư liệu cục bộ thì tải lên trước → gửi tác vụ tạo video → truy vấn định kỳ để lấy URL kết quả → phát, tải xuống hoặc dùng làm tham chiếu cho lượt tiếp theo. Tải lên thành công không có nghĩa là model chắc chắn hỗ trợ loại tư liệu đó; khả năng của model và khả năng lưu trữ là hai chuyện khác nhau.
Quy tắc tích hợp thống nhất: trước tiên điền
modelbằngidchính xác doGET /v1/modelstrả về, sau đó tạo tác vụ bằngPOST /v1/videos, lưuidtrong phản hồi và truy vấn định kỳ quaGET /v1/videos/{id}. Tích hợp mới không dùng/v1/video/generationscũ, không phụ thuộc vàotask_id, và không coicallback_urllà khả năng mà mọi model đều hỗ trợ; khi cần tương thích ổn định, hãy thống nhất dùng truy vấn định kỳ.
1. Quy tắc tối thiểu để tích hợp thống nhất
Nếu cùng một client cần tích hợp nhiều model video, chỉ cần cố định quy trình sau:
- Gọi
GET /v1/modelsbằng API Key hiện tại. - Chọn
idcủa model mà khách hàng thực sự có quyền từ kết quả trả về; không mã hóa cứng tên trong trang model, tên cũ hoặc tên mà tài khoản khác nhìn thấy vào cấu hình toàn cục. - Gửi tác vụ bằng cùng một định dạng yêu cầu
POST /v1/videos. - Chỉ truy vấn tác vụ bằng
idcông khai trong phản hồi; không phân tích hay ghép bất kỳ ID tác vụ nào khác. - Lấy video qua
url,video_urlhoặcresult_urltrong phản hồi hoàn tất.
Các trường chung được khuyến nghị:
| Mục đích | Trường khuyến nghị | Giải thích |
|---|---|---|
| Model | model | Phải là ID model chính xác mà Key hiện tại lấy từ /v1/models |
| Văn bản | prompt | Thường bắt buộc với tạo video chỉ từ văn bản; có được bỏ trống hay không tùy model |
| Thời lượng | duration hoặc seconds | Chọn một trong hai, đơn vị giây; ưu tiên duration |
| Tỷ lệ khung hình | ratio hoặc aspect_ratio | Khuyến nghị dùng để đặt tỷ lệ khung hình; giá trị dùng được tùy theo khả năng của model đích |
| Ảnh tham chiếu | images | Khuyến nghị dùng URL HTTPS công khai hoặc URL assets.88api.ai đã tải lên |
| Video tham chiếu | metadata.referenceVideos | Chỉ dùng khi model đích hỗ trợ |
| Âm thanh tham chiếu | metadata.referenceAudios | Chỉ dùng khi model đích hỗ trợ |
| Khung hình đầu và cuối | metadata.firstFrame, metadata.lastFrame | Đồng thời phải tuân thủ quy tắc khung hình đầu/cuối và quy tắc loại trừ tư liệu của model đích |
Bảng trên là cách viết chung cho phần lớn model. Một số thương hiệu dùng trường khác (ví dụ với Wan, khung hình đầu, khung hình cuối và tư liệu tham chiếu nên dùng mảng media; trường tư liệu không đọc được sẽ trả lỗi 400); hãy theo Quy chuẩn theo từng thương hiệu.
size là trường tương thích mà một số model và client cũ sử dụng. Client mới nên ưu tiên ratio hoặc aspect_ratio và chọn giá trị cụ thể theo mô tả khả năng của model đích.
Trong các ví dụ tiếp theo của trang này, <MODEL_ID> đều là ID model thực lấy từ /v1/models theo các bước trên, không phải một chuỗi cố định mà mọi khách hàng phải dùng chung.
2. Tra cứu nhanh endpoint
| Mục đích | Phương thức và đường dẫn | Giải thích |
|---|---|---|
| Lấy model | GET https://api.88api.ai/v1/models | Trả về ID model mà API Key hiện tại nhìn thấy; lấy kết quả trả về làm chuẩn |
| Gửi yêu cầu tạo | POST https://api.88api.ai/v1/videos | Gửi văn bản và tư liệu tham chiếu, trả về id tác vụ |
| Truy vấn tác vụ | GET https://api.88api.ai/v1/videos/{id} | Truy vấn trạng thái, tiến độ và lỗi |
| Xin tải lên tư liệu | POST https://api.88api.ai/v1/media/uploads | Gửi mã băm, số byte và MIME của tệp, nhận quyền tải lên ngắn hạn |
| Tải lên dữ liệu nhị phân | PUT {upload_url} | Dùng header tải lên được cấp, không gửi API Key |
| Lấy video | GET {url} | Ưu tiên URL kết quả trong phản hồi hoàn tất, không tự ghép đường dẫn |
| Lối vào nội dung cũ | GET https://api.88api.ai/v1/videos/{id}/content | Chuyển hướng tương thích cho video đã lưu trữ; không phải cách tải xuống chung cho mọi kết quả |
| Callback trạng thái cuối | Đặt callback_url khi gửi | Chỉ cho model hỗ trợ callback; các model khác dùng truy vấn định kỳ |
Header yêu cầu
Authorization: Bearer sk-API-Key-của-bạn
Content-Type: application/json
Accept: application/jsonAPI Key phải được lưu ở phía máy chủ, không được đưa vào gói frontend của trình duyệt, mini program hay ứng dụng.
| Thao tác | Xác thực |
|---|---|
| Tạo, truy vấn tác vụ; xin quyền tải lên | Authorization: Bearer ..., chỉ gửi tới API api.88api.ai |
| Tải tệp lên | Dùng nguyên X-Media-Upload-Token và Content-Type trong headers |
| Đọc tư liệu công khai | Địa chỉ assets.88api.ai không cần Bearer, Cookie hay đăng nhập |
Đọc ẩn danh không có nghĩa là tải lên ẩn danh, cũng không công khai chi tiết tác vụ. Ai có URL tư liệu công khai đều có thể đọc tệp trong thời hạn hiệu lực; đừng coi URL là cơ chế cách ly quyền riêng tư nghiêm ngặt. Không chuyển tiếp API Key của bạn tới địa chỉ tư liệu, địa chỉ kết quả chính thức hay đích chuyển hướng.
Lấy ID model mà tài khoản hiện tại được dùng
ID model không cố định giống nhau cho mọi tài khoản. Khi client tích hợp lần đầu hoặc làm mới danh sách model định kỳ, hãy chạy trước:
curl 'https://api.88api.ai/v1/models' \
--header 'Authorization: Bearer sk-xxxx'Chọn model từ data[].id trong phản hồi và đặt nguyên giá trị đó vào trường model của các yêu cầu POST /v1/videos tiếp theo. Không tự ghép ID theo tên hiển thị của model, cũng không coi tên model từ tài khoản khác hoặc tài liệu cũ là chắc chắn dùng được với tài khoản hiện tại.
{
"object": "list",
"data": [
{
"id": "<MODEL_ID>",
"object": "model",
"owned_by": "88api"
}
]
}3. Yêu cầu gửi tiêu chuẩn
Yêu cầu tạo video từ văn bản tối thiểu
curl --request POST 'https://api.88api.ai/v1/videos' \
--header 'Authorization: Bearer sk-xxxx' \
--header 'Content-Type: application/json' \
--data-raw '{
"model": "<MODEL_ID>",
"prompt": "Siêu xe màu bạc trong thành phố đêm mưa, máy quay góc thấp bám theo, phản chiếu ánh đèn neon, chất điện ảnh",
"duration": 8,
"ratio": "16:9"
}'duration cũng có thể viết thành seconds dạng chuỗi:
{
"model": "<MODEL_ID>",
"prompt": "Flycam bờ biển lúc bình minh, mây trôi chậm",
"seconds": "8",
"ratio": "16:9"
}Các trường yêu cầu chung
| Trường | Kiểu | Bắt buộc | Giải thích |
|---|---|---|---|
model | string | Có | ID model chính xác mà API Key hiện tại lấy qua GET /v1/models |
prompt | string | Có điều kiện | Prompt văn bản; chỉ một số model cho phép bỏ trống khi có tư liệu tham chiếu |
negative_prompt | string | Không | Prompt phủ định cho model đa tham chiếu; với Veo cũng có thể viết là metadata.negativePrompt |
duration | integer | Không | Thời lượng video, đơn vị giây; chọn một trong hai với seconds |
seconds | string | Không | Thời lượng video dạng chuỗi, ví dụ "8" |
ratio | string | Không | Trường tỷ lệ khung hình khuyến nghị, ví dụ 16:9, 9:16 |
aspect_ratio | string | Không | Bí danh tương thích của ratio; giá trị dùng được tùy theo khả năng của model đích |
size | string | Không | Trường tương thích; tích hợp mới không dựa vào nó để truyền tỷ lệ khung hình |
resolution | string | Không | Chỉ dùng khi model đích hỗ trợ, ví dụ 480p, 720p, 1080p, 4k |
image | string | Không | URL của một ảnh tham chiếu |
images | string[] | Không | Mảng URL ảnh tham chiếu, cách dùng khuyến nghị |
video | string | Không | URL của một video tham chiếu; Gemini Omni bắt buộc dùng trường cấp gốc này |
videos | string[] | Không | Mảng video tham chiếu; các model đa tham chiếu khác dùng metadata.referenceVideos |
seed | integer | Không | Hạt giống ngẫu nhiên |
generateAudio / generate_audio | boolean | Không | Bật tạo âm thanh đồng bộ trên model hỗ trợ; chỉ dùng khi khả năng của model cho phép |
camera_control | object | Không | Điều khiển máy quay; chỉ dùng khi model tương ứng hỗ trợ rõ ràng |
callback_url | string | Không | Chỉ dùng khi model đích hỗ trợ callback rõ ràng; tích hợp mới mặc định không gửi |
metadata | object | Không | Các trường mở rộng như video tham chiếu, âm thanh tham chiếu, khung hình đầu và cuối |
Cách yêu cầu độ phân giải
Endpoint tạo là thống nhất, nhưng cách chọn độ phân giải của từng model có thể khác nhau. Trước tiên hãy dựa vào ID model do GET /v1/models trả về và mô tả khả năng của model.
Model độ phân giải cố định: chọn độ phân giải qua ID model
Một số model đã cố định mức đầu ra trong tên hoặc ID model. Khách hàng nên lấy từ GET /v1/models các ID mà tài khoản hiện tại thực sự dùng được, rồi chọn trực tiếp model có mức tương ứng:
{
"model": "<FIXED_RESOLUTION_MODEL_ID>",
"prompt": "Một chiếc xe chậm rãi chạy qua con phố trong cảnh đêm thành phố",
"duration": 8,
"ratio": "16:9"
}Với model độ phân giải cố định, resolution không thể tạm thời thay đổi mức đầu ra. Kể cả khi client gửi kèm resolution, cũng đừng coi đó là cách ghi đè khả năng của model.
Model chọn được độ phân giải: dùng trường resolution
Một số model có thể hỗ trợ nhiều độ phân giải; khi đó hãy truyền resolution viết thường trong yêu cầu:
{
"model": "<MULTI_RESOLUTION_MODEL_ID>",
"prompt": "Một chiếc xe chậm rãi chạy qua con phố trong cảnh đêm thành phố",
"duration": 8,
"resolution": "720p",
"ratio": "16:9"
}Độ phân giải và giá trị thực sự dùng được vẫn theo /v1/models của API Key hiện tại, mô tả model và kiểm tra phía máy chủ. Nếu client cần tương thích với nhiều model, có thể giữ trường resolution: model hỗ trợ trường này dùng nó để chọn mức đầu ra, còn model mức cố định lấy model làm chuẩn. Không dùng quality, vquality hoặc tự sửa tên model để lách giới hạn khả năng của model; tổ hợp không được hỗ trợ sẽ trả về 400.
4. Ảnh, video và âm thanh tham chiếu
3.1 Ảnh tham chiếu
Nhiều ảnh thống nhất dùng mảng images ở cấp gốc:
{
"model": "<MODEL_ID>",
"prompt": "Giữ nhất quán khuôn mặt, trang phục và tông màu của nhân vật, chậm rãi bước đi bên bờ biển, ánh sáng dịu chất điện ảnh",
"duration": 10,
"ratio": "16:9",
"images": [
"https://cdn.example.com/character-front.jpg",
"https://cdn.example.com/character-side.jpg"
]
}Một ảnh cũng có thể dùng image hoặc input_reference, nhưng tích hợp mới nên thống nhất dùng mảng images.
3.2 Video tham chiếu
Với các model hỗ trợ nhiều video tham chiếu trong bảng khả năng, đặt vào metadata.referenceVideos:
{
"model": "<MODEL_ID>",
"prompt": "Tham khảo nhịp cắt cảnh và chuyển động máy quay, nhưng giữ nguyên ngoại hình chủ thể",
"duration": 8,
"ratio": "16:9",
"images": ["https://cdn.example.com/subject.jpg"],
"metadata": {
"referenceVideos": [
"https://cdn.example.com/camera-motion.mp4"
]
}
}3.3 Âm thanh tham chiếu
Với các model hỗ trợ âm thanh tham chiếu trong bảng khả năng, đặt vào metadata.referenceAudios:
{
"model": "<MODEL_ID>",
"prompt": "Nhân vật hát theo nhịp của âm thanh tham chiếu, khẩu hình tự nhiên",
"duration": 10,
"ratio": "16:9",
"images": ["https://cdn.example.com/singer.jpg"],
"metadata": {
"referenceAudios": [
"https://cdn.example.com/voice-reference.mp3"
]
}
}Với ảnh tham chiếu của MiniMax H3, đừng dùng images ở cấp gốc mà hãy dùng metadata.referenceImages, xem Quy chuẩn MiniMax Video API.
3.4 Tư liệu hỗn hợp cho model đa tham chiếu
{
"model": "<MODEL_ID>",
"prompt": "Dùng ngoại hình sản phẩm từ ảnh tham chiếu, nhịp máy quay từ video tham chiếu và không khí âm thanh từ âm thanh tham chiếu để làm quảng cáo công nghệ",
"duration": 12,
"ratio": "16:9",
"images": [
"https://cdn.example.com/product-front.jpg",
"https://cdn.example.com/product-detail.jpg"
],
"metadata": {
"referenceVideos": [
"https://cdn.example.com/motion-reference.mp4"
],
"referenceAudios": [
"https://cdn.example.com/sound-reference.mp3"
]
}
}Không dùng đồng thời nhiều trường bí danh cho cùng một loại tư liệu. Ví dụ, không gửi cùng lúc images ở cấp gốc và metadata.referenceImages; khi có nhiều trường tương thích cùng tồn tại, gateway sẽ chọn một nhóm và không bảo đảm gộp lại.
3.5 Yêu cầu đối với URL tư liệu
- Video và âm thanh tham chiếu dùng URL HTTPS công khai, tải xuống được ẩn danh.
blob:, đường dẫn cục bộ vàdata:video/...không phải giao thức video tham chiếu chung; tệp cục bộ hãy tải lên trước theo mục tiếp theo. - URL không được phụ thuộc vào Cookie, trạng thái đăng nhập trình duyệt, Referer hay header tùy chỉnh.
- Không dùng
localhost, IP mạng riêng, tên dịch vụ Docker hoặc địa chỉ chỉ truy cập được trong mạng nội bộ của bạn. - URL phải còn hiệu lực trong suốt quá trình tạo video; khuyến nghị thời hạn hiệu lực không dưới 60 phút.
- Ảnh nên dùng JPG, PNG hoặc WebP; video nên dùng MP4/MOV; âm thanh nên dùng MP3/WAV.
- Video nên không quá 50 MB mỗi đoạn, âm thanh không quá 15 MB mỗi đoạn; tư liệu quá lớn có thể thất bại ở bước tải xuống hoặc kiểm duyệt.
- Trước khi tham chiếu tư liệu của bên thứ ba, hãy bảo đảm bạn có đủ quyền tác giả, quyền hình ảnh và quyền sử dụng cần thiết.
Trang tư liệu mở được không có nghĩa là tải được byte video: địa chỉ đích phải trả về tệp media thực, không phải trang chia sẻ HTML. URL dùng được cũng không có nghĩa là mã hóa, thời lượng hay kích thước đáp ứng yêu cầu của model đích. Ảnh cho model video Google còn có thể dùng Base64 hoặc tải tệp lên, xem Quy chuẩn Google Video API; video tham chiếu vẫn chỉ nhận URL.
3.6 Tải lên tư liệu cục bộ: xin cấp quyền trước, rồi PUT
Endpoint này cung cấp kho lưu trữ media tạm thời; nó không tạo video, không chuyển mã, không nén và không tự động trích xuất khung hình.
Bước 1: xin quyền tải lên ở phía máy chủ.
POST https://api.88api.ai/v1/media/uploads
Authorization: Bearer sk-xxxx
Content-Type: application/json{
"size": 1234567,
"mime_type": "video/mp4",
"sha256": "<SHA-256 của byte gốc của tệp, mã hóa Base64URL không padding>"
}| Trường | Quy tắc |
|---|---|
size | Số byte của tệp gốc, số nguyên từ 1 đến 100,000,000; không phải độ dài chuỗi Base64 |
mime_type | Phải khớp với định dạng thật của tệp và Content-Type khi tải lên |
sha256 | Bản tóm tắt SHA-256 32 byte mã hóa Base64URL, không có =; không phải chuỗi thập lục phân 64 ký tự |
Hỗ trợ tải lên: video/mp4, video/webm, video/quicktime; audio/mpeg, audio/wav, audio/ogg, audio/mp4, audio/flac; image/png, image/jpeg, image/webp, image/gif. Giới hạn tải lên không phải giới hạn tham chiếu của model; tư liệu vẫn phải đáp ứng giới hạn chặt hơn của model đích.
Minh họa phản hồi HTTP 200 (phần trong dấu ngoặc nhọn là giá trị giữ chỗ, không phải giá trị thật để gọi):
{
"url": "https://assets.88api.ai/media/reference-media/<object-id>.mp4",
"upload_url": "https://assets.88api.ai/media/reference-media/<object-id>.mp4",
"method": "PUT",
"headers": {
"Content-Type": "video/mp4",
"X-Media-Upload-Token": "<scoped-upload-token>"
},
"expires_at": 1789373400
}expires_at ở đây là thời điểm hết hạn của quyền tải lên (giây Unix, khoảng 10 phút), không phải thời hạn lưu tệp; lúc này url cũng chưa có nghĩa là tệp đã tải lên xong. Quyền này chỉ cho phép ghi vào tệp được chỉ định, không truy cập được toàn bộ bucket.
Bước 2: tải dữ liệu nhị phân gốc lên trước khi quyền hết hạn. Dùng nguyên upload_url, method và headers trong phản hồi:
# Các biến sau lấy từ phản hồi xin quyền; không gửi API_KEY tới địa chỉ tải lên.
curl --request PUT "$UPLOAD_URL" \
--header 'Content-Type: video/mp4' \
--header "X-Media-Upload-Token: $UPLOAD_TOKEN" \
--data-binary @reference.mp4Đây không phải multipart/form-data, không dùng -F, cũng không phải Base64 trong JSON. Phải gửi Content-Length, MIME và byte tệp khớp với lúc xin quyền; trình duyệt có thể gửi trực tiếp File/Blob và tự tạo Content-Length. Client phía máy chủ dạng luồng cũng phải cung cấp đúng độ dài, không dùng tải lên chunked với độ dài không xác định.
HTTP 201 nghĩa là tải lên đã hoàn tất, trả về url, size, mime_type, expires_at. expires_at lần này mới là thời hạn của tư liệu (giây Unix, 30 ngày kể từ khi đối tượng được tải lên). Sau khi xác nhận thành công, đặt url vào trường tham chiếu mà model đích yêu cầu. Trình duyệt nên xin quyền qua backend của chính bạn rồi tải lên trực tiếp, không được để lộ API Key dài hạn ở frontend.
Không cho phép ghi đè cùng một địa chỉ tải lên: PUT lặp lại trả về 409, hãy dùng lại địa chỉ đã tải lên thành công. Khi gặp sự cố mạng không rõ kết quả, trước tiên dùng HEAD ẩn danh để kiểm tra URL đó, đừng lập tức xin đối tượng mới. Việc tải lên và tham chiếu không tạo tác vụ tạo video mới.
5. Chế độ khung hình đầu và cuối cho model hỗ trợ
Khung hình đầu và khung hình cuối đặt trong metadata.firstFrame và metadata.lastFrame:
Ví dụ dưới đây áp dụng cho model đa tham chiếu hỗ trợ các trường này. Veo và Gemini Omni cũng nhận metadata.firstFrame và metadata.lastFrame; các cách viết khác xem Quy chuẩn Google Video API.
{
"model": "<MODEL_ID>",
"prompt": "Chuyển mượt từ quảng trường vắng lúc sáng sớm sang cùng bố cục vào ban đêm khi đèn bật sáng",
"duration": 10,
"ratio": "16:9",
"metadata": {
"firstFrame": "https://cdn.example.com/start.jpg",
"lastFrame": "https://cdn.example.com/end.jpg"
}
}Quy tắc:
lastFramekhông thể dùng riêng, phải đồng thời cung cấpfirstFrame.- Phần lớn model hỗ trợ khung hình đầu và cuối không cho phép dùng chung khung hình đầu/cuối với ảnh/video/âm thanh tham chiếu thông thường.
- Khi bảng khả năng của model ghi “loại trừ lẫn nhau”, hãy chọn một trong hai: khung hình đầu và cuối hoặc tư liệu tham chiếu thông thường.
6. Bảng khả năng của các model video hiện tại
Các bảng sau mô tả khả năng công khai của model đã được tổng hợp, không phải ID model cố định khi khách hàng gửi yêu cầu. Yêu cầu thực tế phải dùng id mà API Key hiện tại lấy từ /v1/models. Các tài khoản khác nhau có thể thấy ID model khác nhau; chỉ cần dùng giao thức /v1/videos thống nhất, client không cần biết máy chủ chọn model như thế nào.
Quy chuẩn theo từng thương hiệu
Cách viết tham số và trường tư liệu của các thương hiệu không hoàn toàn giống nhau; trước khi tích hợp, hãy đọc trang của thương hiệu tương ứng:
| Trang thương hiệu | Model |
|---|---|
| Seedance bản chính thức | seedance-2.5官方版, seedance-2.0官方版, seedance-2.0-fast官方版, seedance-2.0-mini官方版 |
| SD bản đám mây | SD2.5, SD2.0 |
| Seedance chuyển tiếp chính thức | Seedance 2.0 Mini (đa độ phân giải), Seedance 2.0 (đa độ phân giải), Seedance 2.0 Fast (đa độ phân giải), Seedance 2.5 (đa độ phân giải) |
veo-3.1, veo-3.1-fast, gemini-omni-flash, gemini-omni-flash-1.1 | |
| Kling | kling-3.0-turbo |
| MiniMax | minimax-h3 (giống minimax_h3) |
| Wan | wan3.0-video, wan3.0-video-prime |
| Grok | grok-imagine-video, grok-imagine-video-1.5 |
Bảng tổng hợp khả năng model
| STT | Khả năng / tên công khai | Thời lượng | Tỷ lệ khung hình | Đầu ra | Giới hạn ảnh / video / âm thanh | Khung hình đầu và cuối | Điều khiển âm thanh |
|---|---|---|---|---|---|---|---|
| 1 | seedance-2.5官方版 | 4–30 giây, mặc định 4 giây | 16:9 9:16 1:1 4:3 3:4 21:9 | 720P | 30 / 10 / 10 | Có, loại trừ với tư liệu thông thường | Không thiết lập được |
| 2 | seedance-2.0官方版 | 4–15 giây, mặc định 4 giây | Như trên | 720P | 9 / 3 / 3 | Có, loại trừ với tư liệu thông thường | Không thiết lập được |
| 3 | seedance-2.0-fast官方版 | 4–15 giây, mặc định 4 giây | Như trên | 720P | 9 / 3 / 3 | Có, loại trừ với tư liệu thông thường | Không thiết lập được |
| 4 | seedance-2.0-mini官方版 | 4–15 giây, mặc định 5 giây | Như trên | 480P/720P, mặc định 480P | 9 / 3 / 3 | Mô tả model không liệt kê chế độ khung hình đầu và cuối | Không có tùy chọn tạo âm thanh |
| 5 | SD2.5 | 4–30 giây | Bắt buộc chỉ định: 16:9 9:16 1:1 4:3 3:4 21:9 | 480P/720P/1080P, mặc định 480P | 30 / 10 / 10 | Có, loại trừ với tư liệu thông thường | Hỗ trợ generate_audio |
| 6 | SD2.0 | 4–15 giây | 1:1 (mặc định) 21:9 16:9 9:16 3:4 4:3 | 480P/720P/1080P/4K, mặc định 480P | 9 / 3 / 3, tổng ba loại tối đa 12 | Có, loại trừ với tư liệu thông thường | Không thiết lập được |
| 7 | Seedance 2.0 Mini (đa độ phân giải) | 4–15 giây; hỗ trợ -1, mặc định 5 giây | adaptive (mặc định) 16:9 4:3 1:1 3:4 9:16 21:9 | 480P/720P | 9 / 3 / 3 | Có, loại trừ với tư liệu thông thường | Mặc định có âm thanh, có thể tắt |
| 8 | Seedance 2.0 (đa độ phân giải) | 4–15 giây; hỗ trợ -1, mặc định 5 giây | Như trên | 480P/720P/1080P/4K | 9 / 3 / 3 | Có, loại trừ với tư liệu thông thường | Mặc định có âm thanh, có thể tắt |
| 9 | Seedance 2.0 Fast (đa độ phân giải) | 4–15 giây; hỗ trợ -1, mặc định 5 giây | Như trên | 480P/720P | 9 / 3 / 3 | Có, loại trừ với tư liệu thông thường | Mặc định có âm thanh, có thể tắt |
| 10 | Seedance 2.5 (đa độ phân giải) | 4–30 giây; hỗ trợ -1, mặc định -1 (tự động) | Như trên | 480P/720P/1080P | 30 / 10 / 10 | Có, loại trừ với tư liệu thông thường | Mặc định có âm thanh, có thể tắt |
| 11 | veo-3.1-fast | 4/6/8 giây; dùng ảnh tham chiếu cố định 8 giây; mỗi lần kéo dài thêm 7 giây | 16:9 9:16 | 720P/1080P/4K | 3 / 0 / 0 | Hỗ trợ khung hình đầu, khung hình đầu và cuối, ảnh tham chiếu | Âm thanh gốc, có thể tắt bằng generate_audio |
| 12 | veo-3.1 | 4/6/8 giây; dùng ảnh tham chiếu cố định 8 giây; mỗi lần kéo dài thêm 7 giây | 16:9 9:16 | 720P/1080P/4K | 3 / 0 / 0 | Hỗ trợ khung hình đầu, khung hình đầu và cuối, ảnh tham chiếu | Âm thanh gốc, có thể tắt bằng generate_audio |
| 13 | gemini-omni-flash | 3–10 giây | 16:9 9:16 | 720P | 10 / 1 / 0 | Hỗ trợ khung hình đầu, khung hình đầu và cuối | Không hỗ trợ |
| 14 | gemini-omni-flash-1.1 | 3–10 giây, mỗi lần kéo dài thêm khoảng 10 giây | 16:9 9:16 | 720P/1080P/4K | 10 / 3 / 0 | Hỗ trợ khung hình đầu, khung hình đầu và cuối | Không hỗ trợ |
| 15 | kling-3.0-turbo | 4–15 giây | 16:9 9:16 1:1 | 720P/1080P/2K/4K, mặc định 720P | 30 (gồm khung hình đầu/cuối) / 10 / 0 | Có, dùng được cùng ảnh tham chiếu | Hỗ trợ generate_audio |
| 16 | minimax-h3 | 4–15 giây, mặc định 5 giây | 16:9 (mặc định) 9:16 1:1 4:3 3:4 21:9 | 768P/1080P/2K (siêu phân giải), mặc định 768P | 9 / – / 3 | Có, loại trừ với tư liệu thông thường | Video luôn có track âm thanh, không thiết lập được |
| 17 | wan3.0-video | 2–30 giây, mặc định 5 giây; hỗ trợ -1 | adaptive (mặc định) 16:9 9:16 1:1 4:3 3:4 21:9 | 480P/720P/1080P, mặc định 1080P | 10 / 5 / 5 (dùng mảng media) | Có, loại trừ với tư liệu thông thường | Không thiết lập được |
| 18 | wan3.0-video-prime | Như trên | Như trên | Như trên | Như trên | Như trên | Không thiết lập được |
| 19 | grok-imagine-video | 1–15 giây, mặc định 8 giây | 16:9 9:16 1:1 4:3 3:4 3:2 2:3 (dùng aspect_ratio) | 480P/720P | 1 / 0 / 0 | Không hỗ trợ | Không hỗ trợ |
| 20 | grok-imagine-video-1.5 | 1–15 giây, mặc định 8 giây | Như trên | 480P/720P/1080P | 1 / 0 / 0 | Không hỗ trợ | Không hỗ trợ |
Số thứ tự trong bảng bắt đầu từ 1, chỉ để tiện đọc, không phải tham số yêu cầu. Tên công khai và dòng khả năng trong bảng cũng chỉ để đối chiếu; khi gọi thực tế phải dùng
idchính xác mà/v1/modelstrả về cho API Key hiện tại, không tự ghép tên hay suy đoán quan hệ ánh xạ.
Quy tắc riêng của từng model
Trường của các thương hiệu khác nhau khá nhiều; dưới đây là những điểm dễ sai nhất, quy tắc đầy đủ xem các trang thương hiệu ở trên:
- Wan
wan3.0-video*: khung hình đầu, khung hình cuối và tư liệu tham chiếu nên gửi trong mảngmedia.metadata.firstFrame/lastFrame/referenceImages/referenceVideos/referenceAudios(kể cả dạng gạch dưới),firstFrame/first_frame/lastFrame/last_frameở cấp gốc vàimagesở cấp gốc (ảnh 1 là khung hình đầu, ảnh 2 là khung hình cuối, tối đa 2) cũng được chuyển thànhmedia. Trường tư liệu không đọc được sẽ trả lỗi 400. - Với Grok,
aspect_ratiovàratiotương đương nhau; khi điền nhiều trường tỷ lệ cùng lúc, các giá trị phải giống nhau. Tối đa 1 ảnh đầu vào. - Ảnh tham chiếu của
minimax-h3dùngmetadata.referenceImages, khung hình đầu/cuối dùngmetadata.firstFrame/lastFrame; ý nghĩa củaimagesở cấp gốc thay đổi tùy tuyến được phân bổ, đừng dựa vào nó. 480P và 4K đã ngừng cung cấp. - Video tham chiếu của Veo và Gemini Omni dùng
video/videosở cấp gốc, không dùngmetadata.referenceVideos. - Seedance chuyển tiếp chính thức cũng nhận các trường số ít
image,input_reference,video,audiolàm tư liệu tham chiếu, cùng một tư liệu điền lặp lại chỉ được tính một lần;sizemâu thuẫn vớiratio,aspect_ratiohoặcresolutionsẽ trả về 400. Nhóm mô hình này còn hỗ trợ thư viện chân dung ảo, bản nháp 2.5, khung hình cuối, tìm kiếm web, hủy tác vụ đang xếp hàng và ID tác vụ chính thức; xem Seedance chuyển tiếp chính thức. SD2.5bắt buộc chỉ định rõ tỷ lệ khung hình, không hỗ trợauto.- Seedance bản chính thức,
SD2.5,SD2.0vàkling-3.0-turbomỗi dòng chỉ có một tên model; dùngresolutionđể chọn mức độ phân giải và tính phí theo mức đó. Nếu không truyền, dùng mức thấp nhất của dòng model; mức không được hỗ trợ trả về 400. Các tên cũ có hậu tố mức độ phân giải (ví dụSD2.5 720P,SD2.0 4K) vẫn gọi được nhưng cố định theo mức trong tên, và không còn hiển thị trong quảng trường model. Các tên Kling cũ có hậu tố mức độ phân giải đã ngừng cung cấp.
7. Phản hồi khi gửi
Sau khi gửi thành công, ID tác vụ công khai được trả về ngay:
{
"id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"object": "video",
"model": "<MODEL_ID>",
"status": "queued",
"progress": 0,
"created_at": 1788249600
}Hãy lưu id. Endpoint tiêu chuẩn không bảo đảm trả về task_id; tích hợp mới bắt buộc dùng id.
HTTP 200 nghĩa là “tác vụ đã được tiếp nhận”, không có nghĩa là video đã tạo xong.
8. Truy vấn định kỳ tác vụ
curl 'https://api.88api.ai/v1/videos/task_xxxxxxxxxxxxxxxxxxxxxxxx' \
--header 'Authorization: Bearer sk-xxxx'Trạng thái thống nhất
status | Ý nghĩa | Hành động của client |
|---|---|---|
queued | Đã tiếp nhận, đang xếp hàng | Tiếp tục chờ |
in_progress | Đang tạo | Tiếp tục chờ |
completed | Đã hoàn tất | Đọc url được trả về để phát, tải xuống hoặc tham chiếu lại |
failed | Đã thất bại | Đọc error.code và error.message |
unknown | Trạng thái không xác định | Thử lại sau giây lát; nếu kéo dài, liên hệ hỗ trợ |
Ví dụ phản hồi hoàn tất:
{
"id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"object": "video",
"model": "<MODEL_ID>",
"status": "completed",
"progress": 100,
"created_at": 1788249600,
"completed_at": 1788250200,
"url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4",
"video_url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4",
"result_url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4"
}Ví dụ phản hồi thất bại:
{
"id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"object": "video",
"model": "<MODEL_ID>",
"status": "failed",
"progress": 100,
"error": {
"code": "video_generation_failed",
"message": "Tạo video thất bại"
}
}Chiến lược truy vấn định kỳ
- Sau khi gửi, chờ 3–5 giây rồi mới truy vấn lần đầu.
- Khuyến nghị truy vấn mỗi 10–15 giây một lần, không truy vấn mỗi giây.
- Client tương tác có thể dùng ngân sách chờ 15 phút; phía máy chủ có thể lưu ID tác vụ để tiếp tục truy vấn hoặc nhận callback. Client ngừng chờ không có nghĩa là tác vụ thất bại, bị hủy hay được hoàn tiền.
- Trong lúc
queuedhoặcin_progress, không gửi lại cùng tác vụ, nếu không có thể bị tính phí trùng. - Khi đồng thời cấu hình callback, truy vấn định kỳ có thể làm cơ chế dự phòng.
Thời gian chờ của một yêu cầu HTTP, tổng thời gian chờ của client và thời hạn tác vụ phía máy chủ là các khái niệm khác nhau. Đừng coi 15 phút là bảo đảm máy chủ chắc chắn kết thúc tác vụ, cũng đừng chỉ dựa vào progress=100 để kết luận thành công; hãy lấy status làm chuẩn. Sau khi khôi phục trang hoặc mạng, có thể tiếp tục truy vấn tác vụ ban đầu.
9. Callback (Webhook)
Mục này chỉ áp dụng cho model hỗ trợ callback rõ ràng. Model video Google (Veo, Gemini Omni) và các model khác chưa hỗ trợ callback rõ ràng hãy dùng truy vấn định kỳ, không đặt callback_url.
Thiết lập khi gửi
{
"model": "<MODEL_ID>",
"prompt": "Flycam quay thành phố cyberpunk",
"duration": 8,
"size": "16:9",
"callback_url": "https://api.customer.example/webhooks/88api/video"
}callback_url phải:
- là URL HTTP(S) truy cập được từ Internet; môi trường production rất nên dùng HTTPS;
- không quá 2048 ký tự;
- không trỏ tới IP mạng riêng,
localhost, địa chỉ link-local hoặc cổng bị hạn chế; - trả về bất kỳ phản hồi
2xxnào trong vòng 15 giây.
Callback chỉ được gửi ở trạng thái cuối:
video.completedvideo.failed
Header của callback
Content-Type: application/json
User-Agent: NewAPI-Task-Callback/1.0
X-NewAPI-Event: video.completed
X-NewAPI-Delivery: evt_task_xxx_completed
X-NewAPI-Timestamp: 1788250200
X-NewAPI-Signature: sha256=<hex-hmac>Sự kiện hoàn tất
{
"id": "evt_task_xxxxxxxxxxxxxxxxxxxxxxxx_completed",
"type": "video.completed",
"created_at": 1788250200,
"data": {
"task_id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"model": "<MODEL_ID>",
"status": "completed",
"progress": "100%",
"output_url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4",
"created_at": 1788249600,
"completed_at": 1788250200
}
}Sự kiện thất bại
{
"id": "evt_task_xxxxxxxxxxxxxxxxxxxxxxxx_failed",
"type": "video.failed",
"created_at": 1788250200,
"data": {
"task_id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"model": "<MODEL_ID>",
"status": "failed",
"progress": "100%",
"error": "Tạo video thất bại",
"created_at": 1788249600,
"completed_at": 1788250200
}
}Xác minh chữ ký callback
Khóa ký là toàn bộ API Key đã dùng khi gửi tác vụ đó (gồm cả tiền tố sk-). Chuỗi gốc được ký là:
X-NewAPI-Timestamp + "." + byte gốc của thân yêu cầuVí dụ xác minh bằng Node.js:
import crypto from "node:crypto";
import express from "express";
const app = express();
// Phải giữ lại thân yêu cầu gốc trước, rồi mới phân tích JSON.
app.use(
express.json({
verify: (req, _res, buffer) => {
req.rawBody = buffer;
},
}),
);
app.post("/webhooks/88api/video", (req, res) => {
const timestamp = req.header("X-NewAPI-Timestamp") || "";
const timestampNumber = Number(timestamp);
if (
!Number.isFinite(timestampNumber) ||
Math.abs(Date.now() / 1000 - timestampNumber) > 300
) {
return res.status(401).send("stale timestamp");
}
const received = (req.header("X-NewAPI-Signature") || "").replace(
/^sha256=/,
"",
);
const secret = process.env.API_KEY; // toàn bộ sk-xxxx
const signed = Buffer.concat([
Buffer.from(`${timestamp}.`, "utf8"),
req.rawBody,
]);
const expected = crypto
.createHmac("sha256", secret)
.update(signed)
.digest("hex");
const valid =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!valid) return res.status(401).send("invalid signature");
// Khử trùng lặp lũy đẳng bằng X-NewAPI-Delivery hoặc req.body.id.
console.log(req.body.type, req.body.data.task_id);
return res.sendStatus(204);
});Thử lại callback và tính lũy đẳng
- Khi callback hết thời gian chờ, lỗi mạng hoặc trả về mã không phải
2xx, 88API sẽ thử lại với độ trễ tăng theo cấp số nhân. - Thời gian chờ mỗi yêu cầu là 15 giây, tối đa 8 lần thử, độ trễ tối đa giữa các lần là 15 phút.
- Cùng một sự kiện có thể được gửi nhiều lần. Client bắt buộc dùng
X-NewAPI-Deliveryhoặcidcủa sự kiện để khử trùng lặp lũy đẳng. - Khuyến nghị từ chối callback lệch hơn 5 phút so với giờ của máy chủ bạn, để giảm rủi ro phát lại.
- Khuyến nghị xác minh chữ ký, lưu sự kiện rồi trả về
2xxngay; logic nghiệp vụ tốn thời gian hãy đưa vào hàng đợi bất đồng bộ của riêng bạn.
10. Lấy tệp video
Sau khi tác vụ chuyển sang completed, ưu tiên dùng url trong kết quả truy vấn; client tương thích có thể đọc dự phòng video_url / result_url, còn callback dùng data.output_url. Các trường này là kết quả do máy chủ giao, không tự dựng đường dẫn media từ ID tác vụ hay ID nội bộ.
# RESULT_URL lấy nguyên từ phản hồi hoàn tất; không gửi API Key tới máy chủ media.
curl --fail --location "$RESULT_URL" --output result.mp4Lưu ý:
- Client phải cho phép chuyển hướng HTTP 3xx;
curlcần kèm--location. - Kết quả được lưu trữ trên trang dùng địa chỉ ẩn danh
https://assets.88api.ai/media/...; kết quả chính thức đáp ứng điều kiện liên kết trực tiếp an toàn giữ nguyên URL gốc, không bắt buộc đổi sang tên miền của trang. - Các sản phẩm khác không thể công khai trực tiếp hoặc không thể ánh xạ rõ ràng có thể tiếp tục trả về địa chỉ tương thích kèm tham số truy cập. Hãy giữ nguyên toàn bộ URL và các tham số cần thiết mà máy chủ trả về, không tự xóa tham số hay thay tên miền; không thêm tham số truy vấn vào địa chỉ assets (sẽ trả về 400).
/v1/videos/{id}/contentcũ cung cấp chuyển hướng tương thích 307 cho video đã lưu trữ, không nên dùng làm liên kết trực tiếp chính thức hay lối vào bắt buộc cho mọi sản phẩm; khi trả về 404, hãy truy vấn lại tác vụ để lấy địa chỉ kết quả thực tế, đừng tạo lại một cách mù quáng.output_urltrong callback là địa chỉ kết quả không trong suốt, có thể có thời hạn; không phân tích tên miền hay cấu trúc đường dẫn của nó.- Không ghép, lưu hoặc phụ thuộc vào bất kỳ ID tác vụ nào khác; chỉ dùng
idcông khai trong phản hồi khi gửi. - Nếu cần lưu thành phẩm lâu dài, hãy tải về kho lưu trữ đối tượng của riêng bạn sau khi hoàn tất.
9.1 Lưu trữ, phát và tham chiếu giữa các model
- Tư liệu tải lên trang và video lưu trữ được giữ 30 ngày kể từ khi mỗi đối tượng được tải lên; đọc lại, truy vấn tác vụ cũ hay tham chiếu lại đều không gia hạn, cũng không tải lên bản mới. URL kết quả chính thức theo thời hạn hiệu lực của nguồn, không cam kết 30 ngày.
- Không có tham số chữ ký và không cần đăng nhập không có nghĩa là lưu vĩnh viễn; tệp hết hạn trả về 410, sau khi bị dọn theo vòng đời có thể trả về 404. Bản ghi tác vụ còn tồn tại không có nghĩa là tệp nhị phân vẫn còn.
- Tư liệu công khai hỗ trợ GET, HEAD, Range một đoạn và đọc chéo nguồn từ trình duyệt. Có thể đọc
X-Media-Expires-At(giây Unix); Range thành công thường trả về 206. Bộ nhớ đệm không kéo dài thời hạn ban đầu, cũng không bảo đảm mọi khu vực có cùng tốc độ tải xuống. - Kết quả do Veo tạo có thể dùng làm đầu vào cho các model khác hỗ trợ video tham chiếu, với điều kiện địa chỉ còn hiệu lực và định dạng, kích thước, thời lượng đáp ứng yêu cầu của model đích. Đặt trực tiếp URL kết quả vào trường tham chiếu của model đó, không cần tải xuống rồi tải lên lại; bản thân Veo chỉ nhận video đầu vào khi kéo dài video, không hỗ trợ video tham chiếu.
{
"model": "<MODEL_ID>",
"prompt": "Giữ nguyên chủ thể và chuyển động của video tham chiếu, tiếp nối cảnh quay",
"duration": 4,
"ratio": "16:9",
"metadata": {
"referenceVideos": ["<URL HTTPS đầy đủ của kết quả do tác vụ trước trả về>"]
}
}11. Ví dụ JavaScript đầy đủ về truy vấn định kỳ
Node.js 22+; ở phía máy chủ, đặt API_KEY, MODEL_ID và REFERENCE_FILE (đường dẫn tệp MP4). MODEL_ID phải lấy từ phản hồi GET /v1/models của API Key hiện tại. Đặt TASK_ID để tiếp tục trực tiếp tác vụ cũ mà không tải lên hay tạo lại. Ví dụ sẽ tạo một lần tạo video có tính phí, cuối cùng chỉ in thân yêu cầu cho lượt tiếp theo, không tự động tạo lần thứ hai. Để dễ đọc, ví dụ dùng bộ đệm tệp; khi xử lý hàng loạt tệp lớn, hãy giới hạn số lượng đồng thời.
// video-api-example.mjs — Node.js 22+, run with API_KEY, MODEL_ID, and REFERENCE_FILE.
import { readFile, stat } from "node:fs/promises";
import { createHash } from "node:crypto";
const apiKey = process.env.API_KEY;
if (!apiKey) throw new Error("Set API_KEY on your server");
const baseUrl = "https://api.88api.ai";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function apiJSON(path, body) {
// No automatic POST retry: a timed-out create may already have been accepted.
const response = await fetch(baseUrl + path, {
method: "POST",
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
body: JSON.stringify(body),
signal: AbortSignal.timeout(120000),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
return response.json();
}
async function uploadMedia(file, mimeType) {
const info = await stat(file);
if (!info.isFile() || info.size < 1 || info.size > 100000000) {
throw new Error("File must contain 1–100000000 bytes");
}
const bytes = await readFile(file);
const permit = await apiJSON("/v1/media/uploads", {
size: bytes.length, mime_type: mimeType,
sha256: createHash("sha256").update(bytes).digest("base64url"),
});
const target = new URL(permit.upload_url);
if (target.origin !== "https://assets.88api.ai" || permit.method !== "PUT") {
throw new Error("Unexpected upload destination; do not send credentials");
}
const response = await fetch(target, {
method: "PUT", headers: permit.headers, body: bytes,
redirect: "error", signal: AbortSignal.timeout(120000),
});
// A 409/ambiguous upload is not automatically retried; HEAD permit.url first.
if (response.status !== 201) throw new Error(`Upload HTTP ${response.status}`);
return response.json();
}
async function waitForVideo(id, budgetMs = 15 * 60 * 1000) {
const deadline = Date.now() + budgetMs;
let delay = 4000;
while (Date.now() < deadline) {
await sleep(Math.min(delay, deadline - Date.now()));
const remaining = deadline - Date.now();
if (remaining <= 0) break;
let response, state;
try {
response = await fetch(`${baseUrl}/v1/videos/${encodeURIComponent(id)}`, {
headers: { Authorization: `Bearer ${apiKey}` },
signal: AbortSignal.timeout(Math.min(30000, remaining)),
});
if (response.ok) state = await response.json();
} catch {
delay = Math.min(delay * 2, 60000);
continue; // Retry a read, never create a replacement task.
}
if (response.status === 429 || response.status >= 500) {
const retryAfter = response.headers.get("Retry-After");
const seconds = retryAfter && /^\d+$/.test(retryAfter)
? Number(retryAfter)
: (Date.parse(retryAfter || "") - Date.now()) / 1000;
delay = Number.isFinite(seconds) && seconds > 0
? Math.max(1000, seconds * 1000)
: Math.min(delay * 2, 60000);
await response.body?.cancel();
continue;
}
if (!response.ok) throw new Error(`Task ${id}: HTTP ${response.status}`);
if (state.status === "completed") {
const result = state.url || state.video_url || state.result_url;
if (typeof result !== "string" || new URL(result).protocol !== "https:") {
throw new Error(`Task ${id} completed without a usable HTTPS result URL`);
}
return result; // Keep official URLs and capability query parameters intact.
}
if (state.status === "failed") {
throw new Error(`Task ${id}: ${state.error?.message || "video generation failed"}`);
}
if (!["queued", "in_progress", "unknown"].includes(state.status)) {
throw new Error(`Task ${id}: unexpected status ${state.status}`);
}
delay = 12000;
}
throw new Error(`Stopped waiting for ${id}; save this ID and query later. Not cancelled.`);
}
async function main() {
// Resume a saved task without uploading or creating another paid task.
let id = process.env.TASK_ID;
if (!id) {
if (!process.env.MODEL_ID) throw new Error("Set MODEL_ID from GET /v1/models");
if (!process.env.REFERENCE_FILE) throw new Error("Set REFERENCE_FILE");
const media = await uploadMedia(process.env.REFERENCE_FILE, "video/mp4");
const task = await apiJSON("/v1/videos", {
model: process.env.MODEL_ID, prompt: "Giữ nguyên chủ thể và chuyển động của video tham chiếu, tiếp nối cảnh quay",
duration: 4, ratio: "16:9", metadata: { referenceVideos: [media.url] },
});
id = task.id;
if (!id) throw new Error("Create response did not contain a task ID; do not blindly retry");
console.log("Save task ID:", id); // Persist to your database in production.
}
const resultURL = await waitForVideo(id);
console.log("Result URL:", resultURL); // This grants media access; do not log publicly.
// This only shows the NEXT request body; it does not create a second paid task.
console.log(JSON.stringify({
model: process.env.MODEL_ID, prompt: "Giữ nguyên chủ thể và chuyển động của video tham chiếu, tiếp nối cảnh quay",
duration: 4, ratio: "16:9", metadata: { referenceVideos: [resultURL] },
}, null, 2));
}
await main();12. Xử lý lỗi và thử lại
| Tình huống | Khuyến nghị xử lý |
|---|---|
| HTTP 400 | Kiểm tra tên model, thời lượng, tỷ lệ khung hình, số lượng tư liệu và vị trí trường |
| HTTP 401 | API Key bị thiếu, sai hoặc đã mất hiệu lực |
| HTTP 403 | Key hiện tại không có quyền với model hoặc nhóm |
| HTTP 404 | Tác vụ không tồn tại, không thuộc tài khoản hiện tại, hoặc thành phẩm chưa sẵn sàng |
| Tải lên HTTP 409 | Đối tượng chỉ định đã tồn tại và không thể ghi đè; dùng HEAD xác nhận trước rồi dùng lại địa chỉ đã thành công |
| Media HTTP 410 | Tệp đã hết hạn; đọc và tham chiếu lại không gia hạn, sau khi bị dọn cũng có thể là 404 |
| Tải lên HTTP 415 | Chữ ký tệp không khớp với MIME đã khai báo; không thể chỉ đổi phần mở rộng để giả làm định dạng khác |
| Media HTTP 416 | Range vượt ngoài phạm vi tệp hoặc định dạng không hỗ trợ; dùng HEAD lại để xác nhận kích thước |
| HTTP 429 | Gửi yêu cầu quá nhanh hoặc bị giới hạn hạn mức; theo Retry-After hoặc độ trễ tăng theo cấp số nhân |
| HTTP 5xx | Lỗi dịch vụ tạm thời; yêu cầu truy vấn có thể thử lại với độ trễ |
status=failed | Truy vấn HTTP thành công nhưng tạo video thất bại; đọc error.message |
| Tải tư liệu thất bại | Xác nhận URL truy cập được từ Internet, chưa hết hạn, không có chống hotlink hay phụ thuộc xác thực |
unsupported_reference_media | Model không hỗ trợ loại tham chiếu này; tải lên hay đổi tên miền đều không giải quyết được |
must be a public HTTPS URL | Tệp cục bộ hãy tải lên trước; không thể gửi Blob, Data URL, HTTP hoặc địa chỉ cần đăng nhập |
input_download_failed | Kiểm tra khả năng truy cập thực tế của dịch vụ đích, DNS/mạng và thời hạn của media, không chỉ xem máy của bạn có mở được hay không |
| Bị chặn bởi kiểm duyệt nội dung | Điều chỉnh prompt hoặc tư liệu tham chiếu, không thử lại nguyên trạng vô hạn |
POST /v1/videos hiện chưa cung cấp bảo đảm lũy đẳng theo khóa do khách hàng tự định nghĩa. Nếu khách hàng gặp hết thời gian chờ mạng sau khi đã gửi yêu cầu đầy đủ, đừng gửi lại ngay một cách mù quáng, nếu không có thể tạo và bị tính phí nhiều tác vụ.