Video và việc sinh nội dung
Dựng video từ kịch bản có sẵn, hoặc nhờ AI viết kịch bản trước rồi mới đem đi dựng.
Vòng đời một video
POST /videos nhận việc và trả về ngay — video chưa dựng xong ở thời điểm đó. Theo dõi bằng status khi gọi lại chi tiết:
| status | Nghĩa là |
|---|---|
DRAFT | Đã lưu nhưng chưa có bản dựng |
PENDING | Đã nhận, chờ tới lượt vào hàng đợi |
PENDING_DISPATCH | Chờ chỗ trống trong hàng đợi dựng của tài khoản |
RENDERING | Đang dựng |
GENERATING | Đang sinh video bằng AI, chưa can thiệp được |
READY | Dựng xong, đang chờ bạn gọi đăng |
QUEUED | Đã xếp hàng đăng hoặc đã hẹn giờ |
POSTED | Đã đăng — xem kết quả từng kênh trong mảng targets |
FAILED | Hỏng; đọc errorCode và errorDetail |
Giá trị viết hoa và so sánh đúng từng ký tự. Mảng targets có danh mục riêng ở mức từng kênh: QUEUED, PROCESSING, POSTED, PUBLICLY_AVAILABLE, UNAVAILABLE, FAILED, DRAFT.
Hỏi lại mỗi 10–15 giây là đủ. Bắn dồn không làm khâu dựng nhanh hơn và dễ chạm trần tốc độ.
Tạo video
POST /videos
Bắt buộc gửi header Idempotency-Key — xem Quy ước chung.
{
"title": "Bản tin sáng 22/09",
"script": "Nội dung cho giọng đọc…",
"caption": "Tin nóng sáng nay",
"hashtags": ["tintuc", "sangnay"],
"connectionIds": ["4e1c…"],
"voiceId": "ngochuyennew",
"mediaUrls": ["https://…/anh-1.jpg"],
"keepAsReady": true
}| Trường | Ý nghĩa |
|---|---|
connectionIds | Kênh nhận bài. Lấy id từ GET /channels. |
voiceId | Giọng đọc. Danh sách giọng xem trên giao diện web. |
mediaUrls | Ảnh dùng để dựng hình. Tải lên qua /media rồi lấy url trả về. |
keepAsReady | true = chỉ dựng rồi dừng, chờ bạn gọi đăng. false = dựng xong đăng luôn. |
scheduleAt | Hẹn giờ đăng theo ISO 8601. Bỏ trống là đăng ngay sau khi dựng xong. |
templateId | Mẫu thương hiệu. Lấy từ GET /templates; bỏ trống là dùng mẫu mặc định. |
bgmSource, bgmKey, bgmVolume | Nhạc nền và mức âm lượng của nó. |
youtubeConfig, facebookConfig | Tuỳ chọn riêng của hai nền tảng đó, ví dụ chế độ hiển thị. |
Phản hồi 201 trả về video vừa tạo, kèm mảng warnings. Cảnh báo không chặn việc tạo — hiện chỉ có một loại: kênh đã vượt mốc khuyến nghị số bài trong 24 giờ.
Lượt gọi này trừ credit
Credit bị giữ ngay khi việc vào hàng đợi và quyết toán khi dựng xong. Hỏi GET /credits trước nếu bạn muốn chắc chắn số dư đủ. Xem Cách tính credit.
Đọc và theo dõi
GET /videos?page=1&pageSize=25&status=rendering
GET /videos/{id}Mảng targets nói kết quả trên từng kênh: channelId, platform, status, postUrl khi đã lên, và errorCode khi hỏng. Một video đăng nhiều kênh có thể thành công ở kênh này và hỏng ở kênh kia.
videoUrl là link tải bản dựng, chỉ có giá trị khi dựng xong. Link này có hạn theo chính sách lưu trữ của gói — tải về trước nếu bạn cần giữ lâu.
Đăng và huỷ
Dựng
POST /videos/{id}/render → 202Chỉ áp dụng cho video chưa có bản dựng. Trừ credit như một lượt dựng mới, nên cần header chống trùng.
Đăng
POST /videos/{id}/publish → 202Dành cho video tạo với keepAsReady: true. Thân yêu cầu có thể đổi connectionIds, caption, hashtags, scheduleAt và comment (bình luận đầu tiên tự đăng kèm). Bỏ trống connectionIds thì giữ nguyên các kênh đã gắn lúc tạo; bỏ trống scheduleAt là đăng ngay.
Đường này đòi quyền posts:write chứ không phải videos:write: đây là bước đưa nội dung ra kênh thật, nên tách riêng để bạn cấp được khoá chỉ dựng mà không đăng.
Huỷ đăng
DELETE /videos/{id}Gỡ các lượt đăng đang chờ và đưa video về trạng thái sẵn sàng — bản dựng được giữ lại, nên bạn gọi đăng lại được sau đó. Kênh nào đang đăng dở sẽ chặn thao tác này, và bài đã lên kênh thì không gỡ xuống được bằng đường này.
Không cần header chống trùng: huỷ hai lần cho kết quả giống hệt huỷ một lần.
Sửa tiêu đề, mô tả, hashtag
PATCH /videos/{id}
{ "caption": "Mô tả mới", "hashtags": ["meo"] }Chỉ nhận title, caption, hashtags; trường bỏ trống giữ nguyên. Không dựng lại, không đổi trạng thái hay lịch đăng. Kênh chưa đăng sẽ dùng nội dung mới; bài đã lên kênh thì không đổi. Quyền videos:write, không cần header chống trùng.
Đổi giờ hẹn
Không có đường sửa lịch riêng: gọi DELETE /videos/{id} để gỡ lượt đăng đang chờ (bản dựng được giữ), rồi POST /videos/{id}/publish với scheduleAt mới. Bỏ trống connectionIds là giữ nguyên các kênh cũ.
Nhờ AI viết nội dung
Khi bạn chưa có sẵn kịch bản, /jobs là bước trước đó: xếp một việc cho mô hình, lấy kết quả, rồi mới gọi POST /videos.
POST /jobs
Idempotency-Key: …
{
"kind": "video-talk-script",
"params": { … }
}| kind | Sinh ra |
|---|---|
video-talk-script | Kịch bản cho video lồng tiếng |
storyboard | Kịch bản phân cảnh cho video kiến thức |
storyboard-fit-extras | Bước 2 của luồng trên: khớp phần thừa vào các cảnh |
comic-from-story | Phân cảnh truyện tranh từ một câu chuyện |
campaign-topics | Gợi ý chủ đề cho chiến dịch từ mô tả kênh (briefChannel, count 1–200, language) |
Chỉ nhận các loại liệt kê trong trang này; kind khác bị từ chối với mã 422.
params của mỗi loại được kiểm theo đúng bộ ràng buộc mà giao diện web dùng, nên tên trường gõ sai bị chặn ngay ở lượt gọi chứ không hỏng lặng lẽ ở khâu chạy nền.
GET /jobs/{jobId}state:waiting,active,completed,failed,delayedhoặcunknown.resultchỉ có khistate = completed.errorCodechỉ có khistate = failed. Đây là mã để so sánh, không phải câu để hiển thị.
Lượt gọi trả về 202, không phải 200
Phản hồi chỉ mang jobId và kind. Cố ý không kèm trạng thái: ngay lúc trả lời, việc có thể đã chạy, đã xong, hoặc còn nằm chờ — GET /jobs/{id} mới là chỗ nói được sự thật.
Video kiến thức
Gửi nội dung gốc và một mẫu video kiến thức; máy chủ tự viết lại thành từng cảnh theo mẫu, chọn bố cục, tìm ảnh rồi dựng. Mẫu tạo trên giao diện web, lấy id ở GET /video-templates (chỉ mẫu có kind = storyboard).
POST /knowledge/render → 201
Idempotency-Key: …
{
"templateId": "…",
"script": "Nội dung gốc, 100–30000 ký tự…",
"title": "Vì sao biển mặn",
"voiceId": "ngochuyennew",
"language": "vi"
}- Bắt buộc:
templateIdvàscript. Tuỳ chọn:title,caption,hashtags,language,voiceId,voiceVolume,bgmSource/bgmKey/bgmVolume,advanced,watermark. - Mẫu không phải kiến thức hoặc chưa có kịch bản cảnh trả 422
knowledge_template_required; mẫu không thuộc bạn trả 404 — cả hai đều bị chặn trước khi giữ credit. - Đường này chỉ dựng. Theo dõi bằng
GET /videos/{id}(GENERATING→RENDERING→READY), rồi đăng bằngPOST /videos/{id}/publish. Khi tài khoản đang có nhiều video kiến thức dựng cùng lúc, video mới nằm ởPENDING_DISPATCH— đang chờ tới lượt, không phải lỗi — và tự chuyển sangGENERATING.
Khác với job storyboard
Job storyboard ở trên chỉ để xem trước kịch bản phân cảnh; kết quả của nó không đưa thẳng vào đây được. Đường này tự viết lại nội dung theo đúng kịch bản cảnh của mẫu.
Người dẫn AI và clone video
Hai thể loại này dựng theo cảnh, mỗi cảnh cố định 10 giây, giá tính theo giây. Bước viết nội dung bằng AI mất cả phút nên cả việc dựng cũng đi qua /jobs thay vì POST /videos. Khi việc dựng xong, result.postIds[0] là video trong kho — theo dõi tiếp bằng GET /videos/{id}. Khoá ảnh lấy từ POST /media/upload-ticket.
| kind | Làm gì | Trừ credit |
|---|---|---|
ai-presenter-script | Viết lời thoại từng cảnh theo chủ đề, trả dialogues | Không |
ai-presenter-render | Dựng video người dẫn từ ảnh chân dung; cảnh bỏ trống lời thoại thì AI tự viết | Có |
video-clone-analyze | Đọc 2–5 ảnh chụp video mẫu, trả analysisId (giữ 24 giờ) và bản tóm tắt | Không |
video-clone-render | Dựng video mới theo bản phân tích, từ 1–5 ảnh đầu vào của bạn | Có |
Người dẫn AI
POST /jobs
Idempotency-Key: …
{
"kind": "ai-presenter-render",
"params": {
"presenterImageKey": "uploads/…/presenter.jpg",
"setting": "production_studio",
"hologram": true,
"tone": "blue",
"cameraMove": "dolly_in",
"aspectRatio": "16:9",
"transition": "auto",
"style": "explainer",
"language": "vi",
"topic": "3 xu hướng AI năm nay",
"scenes": [
{ "shot": "medium" },
{ "shot": "close_up", "dialogue": "Cảm ơn bạn đã theo dõi." }
],
"connectionIds": [],
"allowComment": true,
"allowContentReuse": true,
"keepAsReady": true
}
}Clone video
Gọi video-clone-analyze trước với { "frameKeys": [...], "summaryLanguage": "vi" }, đọc bản tóm tắt, rồi mới gọi bước dựng:
{
"kind": "video-clone-render",
"params": {
"analysisId": "…",
"inputImageKeys": ["uploads/…/product.jpg"],
"sceneCount": 3,
"aspect": "source",
"language": "vi",
"changeNote": "Đổi sang sản phẩm son môi",
"connectionIds": [],
"allowComment": true,
"allowContentReuse": true,
"keepAsReady": true
}
}Ảnh đầu vào khác ảnh chụp video mẫu
frameKeys là ảnh chụp màn hình video mẫu, chỉ dùng để phân tích phong cách. inputImageKeys là ảnh của bạn (sản phẩm, nhân vật…) để dựng video mới. Bản phân tích hết hạn sau 24 giờ; quá hạn thì phân tích lại.
