Tạo video Async task Tương thích OpenAI Media proxy Tích hợp API

Tích hợp API tạo video: task, polling và content

Tích hợp tạo video bằng create/poll/content flow, nhận biết edits và extensions, webhook, duration bound và authorized media delivery.

AveMujica API 9 phút đọc

Tích hợp API tạo video là một asynchronous media workflow: bạn tạo job, chờ tới khi hoàn thành hoặc thất bại, rồi download byte qua content URL có thể hết hạn và phải được authorize. Trong OpenAI-compatible gateway theo Videos surface, các route cốt lõi là POST /v1/videos, GET /v1/videos/{task_id} và GET /v1/videos/{task_id}/content. Tài liệu OpenAI chính thức hiện đặt edits, extensions, characters, webhooks và Batch cạnh create/retrieve, trong khi endpoint remix cũ đã deprecated cho công việc mới. Bài viết này chỉ cách tích hợp các flow đó an toàn bằng behavior nhìn thấy trong repository và official documentation, không bịa latency hoặc price.

Bối cảnh ngày 2026-07-15: OpenAI đã công bố deprecation Videos API và alias model Sora 2, shutdown vào 2026-09-24 (OpenAI deprecations). Đừng bắt đầu product dài hạn mới chỉ dựa trên Sora 2. Nếu vẫn vận hành Sora traffic qua gateway, hãy coi đây là migration window: giữ create/poll/content hoạt động, tránh xây UX mới quanh remix-only flow và lập kế hoạch dual-vendor alias ngay.

Trả lời trực tiếp: coi video là task, không phải chat completion

# 1) create
curl -sS https://YOUR_GATEWAY/v1/videos \
  -H "Authorization: Bearer $GATEWAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_VIDEO_MODEL_ALIAS",
    "prompt": "Slow aerial push-in over a misty cedar forest at dawn",
    "seconds": "4",
    "size": "1280x720"
  }'

# 2) poll (prefer webhooks when the upstream supports them; see below)
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID \
  -H "Authorization: Bearer $GATEWAY_KEY"

# 3) download when status=completed
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID/content \
  -H "Authorization: Bearer $GATEWAY_KEY" \
  -o forest.mp4

Các status cần xử lý tường minh, theo video DTO của codebase này, gồm queued, in_progress, completed và failed. Field thường có trên task object gồm id, model, status, progress, created_at, completed_at, expires_at, seconds, size, optional error và lineage field như remixed_from_video_id khi có derivative job.

Luôn kiểm tra lại parameter matrix trong tài liệu hiện tại của vendor—video generation guide và Videos API reference của OpenAI. Vendor khác như Google Veo / Gemini video surface, Runway, Luma, Kling, ByteDance/Volcengine có first-party reference dùng job shape khác. Gateway cũng có thể expose route riêng vendor như /v1/video/generations hoặc Kling-style /kling/v1/videos/* tùy channel adapter. Ưu tiên normalized OpenAI-style task API trong application code khi gateway hỗ trợ.

Surface OpenAI chính thức và route gateway đăng ký hôm nay

Capability, OpenAI docs 2026-07-15Official route / eventThực tế gateway trong repository này
Create videoPOST /v1/videosĐược hỗ trợ như task submit path chính cho OpenAI-style adapter
Retrieve / pollGET /v1/videos/{id}Được hỗ trợ
Download contentGET /v1/videos/{id}/contentĐược hỗ trợ với ownership check
Edit video hiện cóPOST /v1/videos/edits (ưu tiên; remix deprecated)Hiện chưa normalize thành route set hạng nhất của gateway
Extend videoPOST /v1/videos/extensionsHiện chưa normalize
CharactersPOST /v1/videos/characters + characters trên createHiện chưa normalize
Legacy remixPOST /v1/videos/{id}/remix (deprecated cho integration mới)Vẫn được detect/register trên remix-style path cho Sora-style adapter hiện có
Webhooksvideo.completed, video.failedFeature upstream OpenAI; gateway client vẫn nên có poll fallback
BatchDòng Batch API tới POST /v1/videosFeature upstream; không thay thế product job table

Nêu rõ gap này trong architecture review: product code chỉ biết create/poll/content sẽ sống sót khi route đa vendor; product code hard-depend vào remix như nút “edit” sẽ phải chống cả OpenAI deprecation và việc gateway chưa normalize đầy đủ edits/extensions/characters.

Vì sao tích hợp video khó hơn ảnh

ConcernImages, thường gặpVideos, thường gặp
Latencyvài giâyhàng chục giây tới vài phút
API shapethường một responsecreate + wait + content
Payload sizeKB–MBdễ lên nhiều MB
Failure modemoderation / bad sizetimeout dài, partial progress, content hết hạn
Cost riskn và resolutionduration, resolution, edit/extension chain
AuthZ sau createtùy chọnbắt buộc khi download content

Nếu áp chat-completion timeout, ví dụ hard cancel sau 60s mà không polling, video integration sẽ trông “hỏng” dù job thành công sau đó. Thiết kế job table trong application từ ngày đầu.

Data model application được khuyên dùng

video_jobs
  id (your id)
  provider_task_id
  model
  prompt_hash / prompt_text (policy-dependent)
  status
  progress
  seconds
  size
  billing_owner_type / billing_owner_id
  team_id / project_id (nullable)
  content_expires_at
  storage_key (nullable until persisted)
  source_task_id (edit/extension/remix lineage)
  last_error
  created_at / updated_at

Worker update status và progress từ poll hoặc webhook. Khi completed, download worker fetch /content một lần, lưu vào object storage và set storage_key. Khi failed, surface error.message / error.code mà không retry vô hạn.

Bound duration và billing

Duration là billing multiplier. Repository này cap video duration do user cung cấp bằng MaxTaskDurationSeconds = 3600 và reject seconds ngoài range trong validation. Product nên đặt UX maximum chặt hơn, ví dụ 4–12 giây cho preview, dù platform cho dài hơn. Example create chính thức của OpenAI thường dùng bucket giây rời rạc, gồm variant 16/20 giây dài hơn trong tài liệu Sora hiện tại; đừng bịa duration tự do.

Quy tắc integration:

  • parse seconds cẩn thận; DTO có thể giữ dưới dạng string
  • không tin duration do client cung cấp để hiển thị price nếu server chưa re-validate
  • pre-consume quota từ billing owner, user hoặc team, không chỉ actor
  • settle hoặc refund khi task fail sau pre-consume
  • áp cùng discipline cho edit/extension/remix chain để user không vô tình khuếch đại cost

Xem kiến trúc LLM gateway đa tenant cho tách owner và actor, cùng LLM usage log và cost tracking cho field attribution.

Chiến lược chờ: webhook trước, polling làm fallback

Video guide của OpenAI khuyên polling khoảng mỗi 10–20 giây với backoff, và ưu tiên webhook (video.completed / video.failed) khi có. Download URL được document là ngắn hạn, khoảng 1 giờ sau generation trên hướng dẫn OpenAI, nên copy vào storage sớm.

Default thực dụng cho product worker:

  1. Register webhook khi provider và gateway/ops path hỗ trợ signed delivery.
  2. Poll làm safety net: bắt đầu gần 10s, thêm jitter, backoff tới 20–30s dưới load hoặc khi lặp in_progress.
  3. Honor Retry-After khi có.
  4. Cap tổng thời gian chờ bằng hard timeout và terminal local state expired/failed.
  5. Không poll mỗi vài trăm millisecond cho từng browser tab.
type VideoTask = {
  id: string;
  status: "queued" | "in_progress" | "completed" | "failed" | string;
  progress?: number;
  expires_at?: number;
  error?: { message?: string; code?: string };
};

async function sleep(ms: number) {
  await new Promise((r) => setTimeout(r, ms));
}

async function pollVideo(taskId: string, timeoutMs = 15 * 60_000): Promise<VideoTask> {
  const started = Date.now();
  let interval = 10_000;
  while (Date.now() - started < timeoutMs) {
    const res = await fetch(`${process.env.GATEWAY_BASE}/v1/videos/${taskId}`, {
      headers: { Authorization: `Bearer ${process.env.GATEWAY_KEY}` },
    });
    if (res.status === 429) {
      const ra = Number(res.headers.get("retry-after"));
      await sleep(Number.isFinite(ra) ? ra * 1000 : interval);
      interval = Math.min(interval + 5_000, 30_000);
      continue;
    }
    if (!res.ok) throw new Error(await res.text());
    const task = (await res.json()) as VideoTask;
    if (task.status === "completed" || task.status === "failed") return task;
    const jitter = Math.floor(Math.random() * 2_000);
    await sleep(interval + jitter);
    interval = Math.min(Math.floor(interval * 1.2), 30_000);
  }
  throw new Error("video poll timeout");
}

Tune từ completion time đã đo cho model và region của bạn, không theo blog team khác.

AuthZ khi download content và scope workbench

Tạo task không đồng nghĩa được phép stream byte sau đó. Trong gateway đa tenant, /v1/videos/{id}/content phải enforce ownership: cùng user/team/project scope đã tạo job hoặc explicit share policy. Đoán task id cross-tenant phải fail closed.

Workbench path trong repository này:

  • UI: video workbench
  • personal API dưới /api/user/video-workbench
  • team API dưới /api/teams/:team_id/video-workbench với action theo project scope
  • grant riêng như generate video và manage video asset

Điều này khác image workbench chỉ personal. Nếu object storage bắt buộc cho durable workbench playback, hãy configure trước khi hứa permanent history. Fallback play URL trỏ tới /v1/videos/{id}/content vẫn cần live authZ và có thể chịu expires_at.

Edits, extensions, characters và legacy remix

Hướng dẫn OpenAI chính thức cho integration mới:

  • Edits: POST /v1/videos/edits với prompt và source video để thay đổi có mục tiêu; remix đã deprecated cho công việc này.
  • Extensions: POST /v1/videos/extensions để tiếp tục clip completed; tổng duration được stitch, và character không được hỗ trợ trên extension theo guide OpenAI.
  • Characters: POST /v1/videos/characters, rồi reference character ID trên create để giữ consistency.
  • Batch: offline queue các JSONL line POST /v1/videos; batch output có retention window riêng trong tài liệu OpenAI.

Tip integration vẫn áp dụng cho mọi derivative job, gồm legacy remix còn trong gateway này:

  • chỉ cho derivative job khi caller đọc được source task
  • copy tenancy field từ source; đừng bỏ derivative dưới sai project
  • cho user thấy edit/extension/remix là job billable mới, không phải chỉnh miễn phí
  • persist lineage cho support và moderation
  • feature-flag metadata bag riêng vendor; validate duration/size bằng global bound

Cho tới khi gateway normalize edits/extensions/characters, giữ call đó sau explicit adapter flag hoặc native upstream client; đừng giả remix là modern OpenAI path.

Policy persistence

Hãy giả định:

  1. upstream content URL và cả gateway temporary proxy đều có thể hết hạn (expires_at là field hạng nhất; OpenAI document khoảng 1 giờ cho interactive download)
  2. product page cần object key của bạn
  3. thumbnail được derive sau download, không scrape ad hoc từ provider CDN
  4. phải xóa được khi team rời đi hoặc user thực thi retention right

Pipeline an toàn:

completed → authorized content fetch → virus/type sniff nếu cần → object storage put → DB storage_key → serve qua CDN của bạn với app auth.

Bỏ storage “tới lúc cần” là cách demo biến thành incident ticket, đặc biệt đau nếu upstream Videos API cũng đang sunset.

Observability và support

Log ít nhất gateway request id / task id, model alias, seconds, size, status transition, billing owner và actor, webhook hay poll path, cùng final error code. Dashboard nên tách failure class video khỏi chat. Support tooling nên mở task và usage log mà không download full MP4 vào ticket system.

Route thay thế có thể gặp

Tùy channel adapter, operator cũng có thể enable:

  • endpoint kiểu /v1/video/generations
  • Kling /kling/v1/videos/*
  • Gemini/Vertex Veo task adapter
  • vendor task API khác sau Jimeng hoặc route tương tự

Application team không nên hard-code mọi vendor path. Ưu tiên một normalized client (/v1/videos + stable alias) và để gateway map channel. Khi feature chỉ có trên vendor path như motion brush hoặc cinema preset, cô lập sau feature flag và document contract không portable.

Đọc liên quan

Nguồn

Hỏi đáp vận hành

Tôi có thể block HTTP request cho tới khi video xong không?

Chỉ với internal tool ngắn. Product UI nên tạo job record và dùng webhook hoặc polling. Long synchronous request khuếch đại timeout gateway và load balancer.

Nên dùng polling interval nào?

Mặc định gần 10 giây với jitter, backoff tới 20–30 giây, honor Retry-After và ưu tiên webhook video.completed / video.failed khi có. Guide OpenAI nêu khoảng polling 10–20 giây.

Vì sao download content thất bại sau status completed?

Nguyên nhân thường gặp: content hết hạn, sai auth scope, task thuộc project khác hoặc storage/proxy cấu hình sai. Kiểm expires_at và tenancy field trước khi retry generation.

Product mới có nên dùng remix không?

Không làm edit path chính. Official OpenAI docs hướng công việc edit mới tới POST /v1/videos/edits; remix đã deprecated. Gateway này có thể vẫn nhận remix-style route để compatibility—hãy coi đó là legacy bridge, không phải greenfield design.

Tôi có cần video workbench nếu đã gọi /v1/videos không?

Không cho pure backend pipeline. Có khi human cần shared history, preset hoặc quản lý asset theo team scope trong UI.

Worker đầu tiên cần ship

Triển khai một worker tạo video ngắn qua stable non-Sora alias nếu có, hoặc alias Sora rõ ràng là tạm thời với migration date viết trước 2026-09-24. Poll bằng 10s+jitter, webhook tùy chọn, download /content một lần, upload object storage và chứng minh key của team thứ hai không thể download task id. Chỉ sau đó mới nối happy path vào product UI.