Render Video

POSThttps://sangtao.ai/api/v2/render/video

Tài liệu cho Render Video.

Tạo video từ scenes (ảnh/video + audio). Job chạy nền, poll trạng thái qua GET /api/v2/jobs/{jobId}.

Bắt đầu nhanh

Làm theo các bước sau để tạo video đầu tiên qua API:

1

Lấy API Key

Vào Cài đặt → API Key để tạo key. Gửi kèm trong mọi request qua header X-Api-Key.

2

Chọn Layout (bố cục video)

Layout là bố cục video — quyết định vị trí ảnh, chữ, tỷ lệ khung hình (16:9, 9:16, 1:1). Gọi GET /api/v2/assets/video-layouts để xem danh sách layout và slug tương ứng.

3

Tạo Scenes (cảnh quay)

Mỗi scene là một đoạn trong video. Mỗi scene cần 1 hình ảnh (URL hoặc prompt để AI tạo) và tùy chọn audio (URL hoặc text để AI đọc). Hãy tưởng tượng scene như các slide trong bài thuyết trình.

4

Gửi request & theo dõi tiến độ

POST request để nhận jobId. Sau đó poll GET /api/v2/jobs/{jobId} mỗi 3-5 giây cho đến khi status = "Complete" (có URL video) hoặc "Error".

cURL — Minimal example
curl -X POST https://sangtao.ai/api/v2/render/video \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "layoutSlug": "news-vtv",
    "scenes": [{
      "image": { "url": "https://example.com/photo.jpg" },
      "audio": { "text": "Xin chào!", "voiceId": "hoai-my" }
    }]
  }'

Các khái niệm chính

🎬Layout

Bố cục video quyết định giao diện, tỷ lệ khung hình, vị trí các thành phần. Mỗi layout có 1 slug riêng.

🖼️Scene

Một đoạn trong video. Gồm hình ảnh/video, audio (tùy chọn), thời lượng, hiệu ứng và chuyển cảnh.

🎙️Narration vs Per-scene Audio

Narration = 1 audio cho toàn bộ video (chia đều cho các scene). Per-scene audio = mỗi scene có audio riêng. Chọn 1 kiểu, không dùng cả 2.

✨Hiệu ứng & Chuyển cảnh

Effect (ZoomIn, PanLeft...) tạo chuyển động cho ảnh trong scene. Transition (Fade, Dissolve...) là hiệu ứng chuyển giữa các scene. Tự động xoay vòng nếu không chỉ định.

📝Caption / STT

Bật phụ đề với caption.enabled=true. Nếu bạn gửi word timestamps thì dùng luôn, không thì hệ thống chạy STT tự động (tính thêm phí nhỏ).

💰Credits

Credit bị khóa khi tạo job. Sau khi render xong, tính chi phí thực tế và hoàn trả chênh lệch tự động.

Luồng xử lý

POST /render/video

Tạo job

→

Khóa credit

Ước tính phí

→

Tạo media

Ảnh AI, TTS

→

Render video

Ghép video hoàn chỉnh

→

Complete

Có URL video

Tip: Nếu bất kỳ bước nào lỗi, credit tự động được hoàn trả và job status chuyển thành "Error" kèm thông báo lỗi.

Nội dung request

FieldTypeDescription
layoutSlugstringSlug của layout video. Lấy danh sách từ GET /api/v2/assets/video-layouts. Mặc định: server chọn theo aspectRatio
scenes*array1–15 scenes (đoạn video). Mỗi scene cần ít nhất 1 image hoặc 1 video
narrationobject1 audio/TTS dùng cho toàn bộ video, chia đều cho các scene. Không dùng chung với per-scene audio
coverPhotoUrlstringURL ảnh bìa — hiển thị 1 giây đầu video như intro
captionobjectPhụ đề: {enabled: true, preset: "phantom"}. Không gửi words → hệ thống tự chạy STT (tính thêm phí)
backgroundMusicobjectNhạc nền: {trackId: slug từ GET /api/v2/assets/background-tracks} hoặc {audioUrl: "URL nhạc"}, volume: 0.0–1.0
overlaystringHiệu ứng phủ (tuyết, mưa...): slug từ GET /api/v2/assets/overlays. null = không dùng
outputobjectCấu hình đầu ra: {resolution: "720p"|"1080p"|"4k", fps: 24|30|60}. Mặc định 1080p, 30fps
headlineTextstringTiêu đề hiển thị trên layout (nếu layout hỗ trợ)
variablesobjectCặp key-value cho biến template layout (VD: {ticker: "AAPL", date: "2026-01-01"})
webhookUrlstringURL webhook — server sẽ POST đến khi job hoàn thành hoặc lỗi
Important: image vs video: mỗi scene chọn 1, không dùng cả 2. narration vs audio: chọn 1 kiểu — narration (1 audio cho tất cả) hoặc per-scene audio.

Đối tượng Scene

Mỗi scene là một đoạn trong video. Bắt buộc có image hoặc video, audio là tùy chọn.

FieldTypeDescription
imageobjectHình ảnh cho scene. Bắt buộc 1 trong 2: image hoặc video (xem chi tiết bên dưới)
videoobjectVideo clip cho scene. Bắt buộc 1 trong 2: image hoặc video (xem chi tiết bên dưới)
audioobjectAudio cho scene — URL có sẵn hoặc text cho AI đọc (xem chi tiết bên dưới)
durationSecnumberThời lượng scene (giây). Không set → lấy từ audio length. Không có audio → default 4s
keyPhrasestringCâu chữ hiển thị trên video theo vị trí của layout (ví dụ: tiêu đề tin tức)
effectstringHiệu ứng ảnh: ZoomIn, PanLeft, ... Không set → tự động xoay vòng. Video bỏ qua
transitionstringChuyển cảnh sang scene tiếp: Fade, Dissolve, ... Không set → tự động xoay vòng
zoomLevelnumberMức zoom cho hiệu ứng ảnh (1.0–3.0). Mặc định: 1.15
transitionDurationnumberThời lượng chuyển cảnh (giây) (0.1–2.0). Mặc định: 1.0
elementsarrayCác element phủ lên scene (text, logo). Max 15. Xem phần Overlay Elements

Đối tượng Image (ảnh)

Cung cấp URL ảnh có sẵn, hoặc viết prompt để AI tạo ảnh. Mỗi scene chọn 1 cách.

FieldTypeDescription
urlstringURL ảnh có sẵn. Dùng cách này hoặc prompt, không dùng cả 2
promptstringPrompt mô tả để AI tạo ảnh. Cần kèm model
modelstringModel slug cho AI gen ảnh (GET /api/v2/models?category=image). Bắt buộc khi có prompt
fitstring"cover" | "contain" | "fit" | "fill-content". Default: "contain". Xem phần Chế độ Fit bên dưới
aspectRatiostringTỷ lệ ảnh AI gen: "9:16" | "16:9" | "1:1". Mặc định theo layout

Đối tượng Video

Cung cấp URL video clip. Dùng thay image cho các scene cần video thực.

FieldTypeDescription
url*stringURL video clip (.mp4, .webm...)
fitstring"cover" | "contain" | "fit" | "fill-content". Default: "contain". Xem phần Chế độ Fit

Chế độ Fit (hiển thị ảnh/video)

Quyết định cách ảnh/video được co giãn để vừa khung hình. Áp dụng cho cả image.fit và video.fit.

ValueCách hoạt độngMô tả
coverPhóng to + cắt rìaẢnh phủ kín khung hình, cắt bỏ phần thừa. Không có viền đen. Có thể mất 1 phần ảnh ở rìa.
containThu nhỏ + nền blurẢnh nằm gọn trong khung, nền blur phía sau phần trống. Giữ nguyên toàn bộ nội dung, không cắt.
fitThu nhỏ + nền đenGiống contain nhưng nền đen thay vì blur. Ảnh giữ nguyên tỷ lệ, viền đen 2 bên.
fill-contentBlur toàn frame + sharp vùng nội dungDùng với layout có bars (trên/dưới). Ảnh sharp chỉ nằm trong vùng content (giữa 2 bars), blur BG phủ toàn bộ frame kể cả phía sau bars.
Tip: Mặc định là "contain" (nền blur). Dùng "cover" cho ảnh phủ kín, "fill-content" cho layout kiểu tin tức có thanh trên/dưới.

Đối tượng Audio (giọng đọc)

Cung cấp URL audio có sẵn, hoặc text + voiceId để AI đọc. Có thể gửi kèm word timestamps để bỏ qua STT.

FieldTypeDescription
urlstringURL audio có sẵn (.mp3, .wav...). Dùng cách này hoặc text, không dùng cả 2
textstringNội dung để AI đọc (TTS). Cần kèm voiceId
voiceIdstringVoice slug từ GET /api/v2/assets/voices. Bắt buộc khi có text
wordsarrayMảng [{word, offsetMs, durationMs}] — timestamps từng từ. Gửi kèm để bỏ qua STT tự động
Tip: Không set durationSec → thời lượng scene lấy từ audio. Nếu dùng narration → chia đều. Không có audio → mặc định 4s.

Ví dụ request

JSON
{
  "layoutSlug": "news-vtv",
  "scenes": [
    {
      "image": {
        "url": "https://example.com/photo.jpg",
        "fit": "cover"
      },
      "audio": {
        "text": "Cuối con phố nhỏ ở Hội An...",
        "voiceId": "vi-VN-HoaiMyNeural"
      },
      "keyPhrase": "Tiệm đèn lồng",
      "effect": "ZoomIn",
      "transition": "Fade"
    },
    {
      "image": {
        "prompt": "cô gái đứng trước tiệm đèn lồng",
        "model": "nano-banana-pro",
        "fit": "cover"
      },
      "audio": {
        "text": "Những chiếc đèn lồng đỏ rực rỡ...",
        "voiceId": "vi-VN-HoaiMyNeural"
      },
      "effect": "PanRight"
    }
  ],
  "caption": { "enabled": true, "preset": "phantom" },
  "backgroundMusic": {
    "trackId": "fassounds-good-night-lofi",
    "volume": 0.2
  },
  "output": { "resolution": "1080p", "fps": 30 }
}

Phản hồi (200 OK)

JSON
{
  "success": true,
  "data": {
    "jobId": "a1b2c3d4e5f6...",
    "status": "Pending",
    "statusUrl": "/api/v2/jobs/a1b2c3d4e5f6...",
    "durationSec": 65.0,
    "aspectRatio": "16:9",
    "renderCost": 27.0,
    "imageGenCost": 16.0,
    "ttsCost": 1.94,
    "sttCost": 3.25,
    "totalCost": 48.19
  }
}

Theo dõi tiến độ

Poll GET /api/v2/jobs/{jobId} mỗi 3–5 giây cho đến khi status = Complete hoặc Error.

HTTP
// Poll mỗi 3–5 giây
GET /api/v2/jobs/{jobId}

{
  "success": true,
  "data": {
    "jobId": "a1b2c3d4...",
    "status": "Processing",    // Pending → Processing → Complete | Error
    "progress": 45.0,
    "result": "generating_media_2_of_3"
  }
}
BướcTiến độ
generating_script10–15%
generating_media15–40%
generating_media_N_of_M15–40%
rendering40–90%
Complete100%

Hiệu ứng (chỉ ảnh)

ValueMô tả
StaticKhông hiệu ứng
ZoomInZoom vào
ZoomOutZoom ra
PanLeftPan trái
PanRightPan phải
PanUpPan lên
PanDownPan xuống
ZoomInPanUpZoom vào + pan lên
ZoomInPanLeftZoom vào + pan trái
ZoomOutPanRightZoom ra + pan phải
Tip: Không set → auto cycle: ZoomIn → PanRight → ZoomOut → PanLeft → ...

Chuyển cảnh

ValueMô tả
FadeFade in/out
DissolveHòa tan
FadeBlackFade qua đen
SlideLeftTrượt trái
SlideRightTrượt phải
SlideUpTrượt lên
SlideDownTrượt xuống
Tip: Không set → auto cycle: Fade → Dissolve → FadeBlack → Dissolve → ...

Mã lỗi

MãKhi nào
400Thiếu field bắt buộc (layoutSlug, image/video, voiceId khi có text)
402Không đủ credit
404Layout/model/preset/track/overlay không tìm thấy
422Validation lỗi (image+video cùng lúc, narration+audio cùng lúc, quá 15 scene)
429Quá 4 job đang chạy cùng lúc

Ví dụ code

cURL
curl -X POST https://sangtao.ai/api/v2/render/video \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "layoutSlug": "news-vtv",
    "scenes": [{
      "image": { "url": "https://example.com/photo.jpg" },
      "audio": { "text": "Nội dung...", "voiceId": "vi-VN-HoaiMyNeural" }
    }],
    "output": { "resolution": "1080p" }
  }'
JavaScript
const response = await fetch('https://sangtao.ai/api/v2/render/video', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'your-api-key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    layoutSlug: 'news-vtv',
    scenes: [{
      image: { url: 'https://example.com/photo.jpg' },
      audio: { text: 'Nội dung...', voiceId: 'vi-VN-HoaiMyNeural' },
    }],
    output: { resolution: '1080p' },
  }),
})
const { data } = await response.json()
console.log(data.jobId) // Poll GET /api/v2/jobs/{jobId}

Credit & Giá

Note: Credit được estimate lúc tạo job → lock → sau khi render xong tính actual cost → refund chênh lệch nếu có.
ItemCách tính
RenderBase 25 cr (≤60s). Trên 60s: 25 + ceil((duration−60)/10) × 2 cr
AI Image GenTheo model pricing × số ảnh gen
TTS (Free voice)500 ký tự đầu miễn phí, sau đó 1 cr mỗi 200 ký tự
TTS (Pro 10)10 cr mỗi 1.000 ký tự
TTS (Pro 40)40 cr mỗi 1.000 ký tự
TTS (Pro 60)60 cr mỗi 1.000 ký tự
STT (caption)~3 cr/phút audio (chỉ khi caption enabled + không gửi words)