Kênh, media và số liệu

Những endpoint chỉ đọc mà mọi luồng khác đều cần, cộng với tải tệp lên kho media và đăng thẳng video có sẵn.

Kênh đã nối

GET /channels?page=1&pageSize=25

Đây là nơi lấy id để truyền vào connectionIds ở mọi chỗ khác.

TrườngÝ nghĩa
platformyoutube, tiktok, facebook, instagram, …
handleTên hiển thị trên nền tảng, ví dụ @kenhcuatoi
tokenStatushealthy = đăng được ngay. Giá trị khác nghĩa là kênh cần nối lại trên giao diện web.
supportsCommentsNền tảng này có nhận bình luận tự động hay không
followersCountSố người theo dõi lần cập nhật gần nhất

Nối kênh mới phải làm trên giao diện web

Việc đó đi qua màn hình cấp quyền của chính nền tảng. API chỉ đọc danh sách và dùng kênh đã nối.

Số dư credit

GET /credits
{ "available": 1250, "held": 36 }
  • available — tiêu được ngay.
  • held — đang giữ cho việc đang chạy, chưa quyết toán. Việc xong thì phần này trừ thật; việc hỏng thì trả lại.

Hỏi trước mỗi loạt tạo video nếu bạn muốn dừng sớm thay vì để từng lượt gọi hỏng vì thiếu tiền. Xem Cách tính credit.

Báo giá trước khi tạo

POST /credits/estimate

{ "moduleKey": "image-to-video", "serverTier": 1, "durationSec": 10 }

Chỉ đọc bảng giá, không giữ hay trừ gì (quyền credits:read). total là số sẽ bị giữ khi tạo với đúng đầu vào này; serverTiers cho giá và trạng thái nhận việc của từng server. Bỏ trống serverTier là server 1; durationSec (1–300) chỉ ảnh hưởng loại billing = per-second.

Endpoint tạomoduleKey để báo giá
POST /videosnews
POST /knowledge/renderknowledge
POST /storytelling/renderstorytelling
POST /comics/{id}/rendercomic
POST /video-talk/renderđúng moduleKey gửi lên
POST /ai-videomoduleKey gửi lên (bỏ trống là image-to-video)
POST /ad-video/rendervariant của mẫu (product-review, tvc, ugc)
jobs ai-presenter-render / video-clone-renderai-presenter / video-clone, durationSec = số cảnh × 10

Khi nào số thật có thể khác báo giá

  • POST /ai-video và POST /ad-video/render bỏ trống serverTier thì tự chọn server rẻ nhất đang nhận việc, và thời lượng có thể được làm tròn lên theo độ dài clip của server đó. Muốn giá chắc chắn, truyền serverTier khi tạo.
  • AI avatar và điều khiển chuyển động tính theo thời lượng đo từ tệp gửi lên.
  • Trạng thái server là trạng thái chung; lượt tạo thật còn phụ thuộc số ảnh gửi kèm.

Lịch sử credit và lịch sử gọi

GET /credits/transactions?type=spent&from=2026-09-01T00:00:00Z&videoId=…
GET /usage-logs?channel=mcp&outcome=error&apiKeyId=…
GET /usage-logs/stats?channel=api&timeZone=Asia/Ho_Chi_Minh
  • /credits/transactions (quyền credits:read) — mỗi lần số dư đổi, kèm số dư ngay sau đó. type là deposited, spent, refunded hoặc revoked; dòng not_charged ghi nhận video hỏng mà không bị trừ tiền.
  • /usage-logs (quyền usage:read) — mỗi lượt gọi API bằng khoá và mỗi lượt trợ lý AI dùng công cụ MCP: thao tác, mã HTTP, mã lỗi, khoá hoặc ứng dụng đã gọi, thời gian xử lý. Giữ 90 ngày, không lưu nội dung yêu cầu.
  • /usage-logs/stats (quyền usage:read) — tổng lượt gọi, tỉ lệ lỗi, thời gian phản hồi trung bình/p50/p95, số liệu theo mốc thời gian và 10 thao tác gọi nhiều nhất. Mặc định 24 giờ gần nhất, tối đa 90 ngày; mốc chia theo phút, giờ hoặc ngày tuỳ độ dài khoảng, tính theo timeZone (IANA).

Khoảng from sau to bị từ chối với mã 422 thay vì trả danh sách rỗng — rỗng dễ bị đọc nhầm thành "không có gì xảy ra".

Kho media

Tải tệp lên đi qua ba bước. Tệp không đi qua máy chủ API — bạn gửi thẳng lên kho, nên tệp lớn không chiếm băng thông của API và không bị trần kích thước thân yêu cầu.

  1. 1

    Xin phiếu tải lên

    POST /media/upload-ticket
    { "contentType": "video/mp4" }

    Nhận về url, fields, key, expiresAt và maxBytes.

  2. 2

    Gửi tệp lên đúng địa chỉ đó

    POST kiểu multipart tới url, kèm nguyên vẹn các trường trong fields, xếp trước phần tệp. Sai thứ tự là kho từ chối.

  3. 3

    Xác nhận

    POST /media
    { "key": "…", "originalName": "clip.mp4" }

    Chỉ sau bước này tệp mới hiện trong kho và dùng được. Bỏ qua bước xác nhận thì tệp nằm mồ côi và sẽ bị dọn.

GET    /media?limit=25&startingAfter={id}&folderId={id}
GET    /media/{id}
DELETE /media/{id}

Kho media phân trang bằng con trỏ: truyền id của phần tử cuối trang trước vào startingAfter. Lý do ở Quy ước chung.

Chỉ tệp video ở trạng thái ready mới đem đăng được

Video tải lên còn phải qua khâu xử lý. playbackStatus nói tệp đã sẵn sàng chưa — đẩy một tệp chưa ready vào lượt tạo video là hỏng ở tận khâu dựng.

Đăng video có sẵn lên kênh

Video đã tự dựng xong ở nơi khác thì đăng thẳng, không dựng lại và không trừ credit — giống trang Đăng video có sẵn trên giao diện.

POST /media/{id}/publish → 202
Idempotency-Key: …

{
  "title": "Tiêu đề (dùng cho YouTube)",
  "caption": "Mô tả bài đăng",
  "hashtags": ["meo", "hay"],
  "connectionIds": ["…"],
  "scheduleAt": "2026-10-01T10:00:00+07:00",
  "coverMediaId": "…"
}
  • Bắt buộc: title, caption (được để chuỗi rỗng), hashtags (được để mảng rỗng) và ít nhất một connectionIds. Tài khoản phải có gói Upload video; thiếu gói trả 403 upload_video_not_entitled.
  • {id} là tệp video trong kho, đã ở trạng thái ready. Bỏ trống scheduleAt là đăng ngay; hẹn giờ thì phải ở tương lai và không quá 30 ngày (schedule_in_past, schedule_too_far).
  • coverMediaId là một ảnh trong kho làm ảnh bìa; bỏ trống thì lấy khung hình tự trích từ video.
  • Tuỳ chọn thêm giống POST /videos/{id}/publish: allowComment, allowContentReuse (mặc định true), youtubeConfig, facebookConfig, comment.
  • Đòi quyền posts:write và header Idempotency-Key: mỗi lượt gọi tạo một bài mới trên kênh thật, nên gửi lại cùng khoá sau khi mất mạng sẽ nhận về đúng bài cũ thay vì đăng trùng.

Phản hồi là một video mới, kèm warnings nếu kênh đã chạm mốc khuyến nghị số bài trong 24 giờ. Theo dõi kết quả từng kênh qua GET /videos/{id} (targets[]) — xem Video. Đăng nhiều tệp thì gọi lần lượt từng tệp.

Mẫu thương hiệu

GET /templates?page=1&pageSize=25
GET /templates/{id}

Lấy id ở đây rồi truyền vào templateId lúc tạo video hoặc lúc dựng nguồn tin. Phản hồi cố ý gọn: name, kind, themeId và bgmEnabled.

Gần năm mươi trường toạ độ và màu sắc bên trong mẫu không có mặt: đó là cách khâu dựng vẽ ra khung hình, và mang chúng ra ngoài là trói hợp đồng của bạn vào một cách dựng cụ thể. Sửa mẫu làm trên giao diện web.

Số liệu hiệu quả

GET /analytics/overview
GET /analytics/videos?sort=views&limit=20&channelIds=a,b
  • overview trả tổng lượt xem 30 ngày, tỷ lệ tương tác, số bài, người theo dõi mới, biểu đồ theo ngày, và phần chia theo từng kênh.
  • videos trả bảng xếp hạng bài đăng. sort nhận views, likes hoặc recent.
  • channelIds nhận cả kiểu lặp lại (?channelIds=a&channelIds=b) lẫn kiểu ngăn bằng dấu phẩy. Bỏ trống là gộp mọi kênh.

insightIssue nói vì sao số liệu của một kênh không đầy đủ

Trường này trả về mã, không phải câu mô tả — mã là thứ so sánh được, còn câu chữ tuỳ ngôn ngữ và sửa lúc nào cũng được. null nghĩa là lấy được hết.

platformVideoId trong bảng xếp hạng là id của bài trên chính nền tảng đó, không phải id video trong hệ này — đừng đem nó đi gọi GET /videos/{id}.