Bỏ qua, đến nội dung chính
RPT AI Video Studio

Tra cứu

REST API và webhook

REST API là một giao diện HTTP nhỏ dưới /v1 dành cho script và backend: báo giá một clip, tạo clip, đọc và tải tệp, và chạy các lô clip. API dùng cùng token API như MCP, và cùng các giới hạn áp dụng cho nó.

Cơ bản

  • Đường dẫn gốc là /v1 trên máy chủ studio, cùng máy chủ với MCP server. Trong các ví dụ, STUDIO_URL chứa địa chỉ và MCP_API_TOKEN chứa token.
  • Xác thực chỉ bằng bearer token: Authorization: Bearer <token>. Cookie đăng nhập web không bao giờ được đọc. Gọi mà không có token thì lỗi UNAUTHENTICATED (HTTP 401).
  • Tạo token ở trang Nhà phát triển, như trong bắt đầu nhanh. Chế độ, công cụ được phép, phạm vi dự án, số lệnh gọi mỗi phút, trần chi tiêu, số job tính phí cùng lúc và việc tạm khóa đều áp dụng y như qua MCP.
  • Mỗi endpoint cần công cụ MCP cùng mục đích nằm trong danh sách công cụ được phép của token (xem bảng bên dưới). GET /v1/me không cần công cụ nào.
Lệnh gọi đầu tiên: token này là của ai?
export STUDIO_URL="https://<your-studio-host>"
export MCP_API_TOKEN="<your token>"
curl -sS "$STUDIO_URL/v1/me" -H "Authorization: Bearer $MCP_API_TOKEN"
Phản hồi ví dụ của GET /v1/me
{
  "object": "token",
  "workspace_id": "<workspace id>",
  "project_id": null,
  "mode": "execute",
  "environment": "<environment>",
  "tools": ["quote_media_task", "generate_media_task", "get_media_task"],
  "rate_limit_per_minute": 60
}

Các endpoint

Các endpoint REST
EndpointCần công cụLàm gì
GET /v1/mekhông cầnKhông gian làm việc, dự án, chế độ, công cụ được phép và số lệnh gọi mỗi phút của token.
GET /v1/modelslist_video_modelsCác mô hình video bạn có thể chọn, và default_video_model.
POST /v1/media-tasks/quotesquote_media_taskBáo giá một tác vụ media và trả 201. Báo giá miễn phí.
POST /v1/media-tasks/{task_id}/generategenerate_media_taskBắt đầu một tác vụ đã báo giá. Tiêu tiền ngay theo giá đã báo.
GET /v1/media-tasksget_media_taskLiệt kê tác vụ. kind mặc định là video_clip.
GET /v1/media-tasks/{task_id}get_media_taskĐọc một tác vụ.
GET /v1/media-tasks/{task_id}/fileget_media_taskTải tệp. Trả 409 cho đến khi tác vụ ở trạng thái READY.
POST /v1/media-batchescreate_media_batchTạo một lô clip và mặc định bắt đầu nó. Trả 201.
GET /v1/media-batches/{batch_id}get_media_batchĐọc một lô: trạng thái, số lượng và tiến độ.
GET /v1/media-batches/{batch_id}/itemslist_media_batch_itemsLiệt kê các mục. Mục ready có file_url.
GET /v1/openapi.json, GET /v1/docskhông cầnTài liệu OpenAPI và một trang liệt kê các endpoint. Cả hai đều mở: không cần token.

Nội dung báo giá nhận cùng các trường như công cụ MCP quote_media_task; trường lạ bị từ chối. Các trường cho clip video là kind, prompt, duration_seconds, ratio, resolution, route và reference_asset_id. Các loại khác là voice, music, sfx và image. Không gian làm việc không bao giờ nằm trong nội dung gửi lên: một token thuộc về một không gian làm việc.

Báo giá rồi tạo clip

  1. Báo giá clip. Phản hồi có id của tác vụ và state là QUOTED.
  2. Cho người dùng xem giá. Chỉ sau khi họ đồng ý mới tạo clip. Phản hồi có state là QUEUED.
  3. Đọc tác vụ cho đến khi state là READY, hoặc chờ webhook (bên dưới).
  4. Tải tệp.
1. Báo giá (phản hồi có id của tác vụ)
curl -sS -X POST "$STUDIO_URL/v1/media-tasks/quotes" \
  -H "Authorization: Bearer $MCP_API_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"kind": "video_clip", "prompt": "A ceramic mug on a bright table, slow turn", "duration_seconds": 4, "ratio": "9:16"}'
2. Tạo clip, sau khi người dùng đồng ý với giá
export TASK_ID="<id from the quote>"
curl -sS -X POST "$STUDIO_URL/v1/media-tasks/$TASK_ID/generate" \
  -H "Authorization: Bearer $MCP_API_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"
3. Đọc trạng thái, rồi tải tệp
curl -sS "$STUDIO_URL/v1/media-tasks/$TASK_ID" -H "Authorization: Bearer $MCP_API_TOKEN"
curl -sS -o clip.mp4 "$STUDIO_URL/v1/media-tasks/$TASK_ID/file" -H "Authorization: Bearer $MCP_API_TOKEN"

Lô

Gửi bảng dưới dạng csv (văn bản), xlsx_base64 (tệp .xlsx mã hóa base64) hoặc rows (danh sách đối tượng). Ngoài bảng, nội dung nhận các trường sau; trường lạ bị từ chối.

Nội dung của lô
TrườngÝ nghĩa
csv, xlsx_base64, rowsBảng. csv tối đa 2.000.000 ký tự, xlsx_base64 tối đa 4.000.000. Một lô mặc định có 100 dòng.
templateTối đa 3600 ký tự, với các chỗ giữ chỗ {{column}}. Không có thì cột prompt của mỗi dòng là prompt.
route, duration_seconds, ratio, resolution, reference_asset_idCác tùy chọn clip cho mọi dòng; một cột trong bảng thay chúng cho một dòng. Xem Clip video và lô clip.
project_idDự án để gắn lô vào, không bắt buộc.
startMặc định là true: lô bắt đầu ngay. false tạo bản nháp miễn phí để người dùng bắt đầu trong ứng dụng web.
Một lô nháp hai dòng
curl -sS -X POST "$STUDIO_URL/v1/media-batches" \
  -H "Authorization: Bearer $MCP_API_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"rows": [{"product": "Ceramic mug"}, {"product": "Linen shirt"}], "template": "Slow turntable shot of a {{product}} on a bright table", "ratio": "9:16", "start": false}'

Phản hồi có id của lô, status (ở đây là draft) và item_count. Đọc lô bằng GET /v1/media-batches/{batch_id} và các mục bằng GET /v1/media-batches/{batch_id}/items, có thể kèm state=ready.

Idempotency-Key

  • Mọi POST cần header Idempotency-Key dài từ 8 đến 200 ký tự ASCII in được. UUID là một khóa tốt. Không có khóa hợp lệ thì lệnh gọi lỗi V1_IDEMPOTENCY_KEY_REQUIRED (HTTP 400).
  • Khóa có phạm vi theo không gian làm việc và theo route. Lặp lại một khóa trên cùng route trả về kết quả đầu tiên và không tạo thêm báo giá, tác vụ hay lô nào. Cùng khóa trên route khác là một yêu cầu khác.
  • Tạo khóa mới cho mỗi yêu cầu mới; chỉ dùng lại khóa để thử lại đúng lệnh gọi đó sau khi hết thời gian chờ.

Giới hạn tốc độ, lỗi và phân trang

  • Mọi phản hồi mang X-RateLimit-Limit, X-RateLimit-Remaining và X-RateLimit-Reset. Giá trị reset là thời điểm unix tính bằng giây, khi cửa sổ một phút hiện tại kết thúc. Phản hồi 429 còn mang Retry-After.
  • Lệnh gọi thất bại trả {code, message, retryable, request_id}. message theo header Accept-Language của yêu cầu. Hãy nêu request_id khi nhờ hỗ trợ.
  • Các mã là những mã trong bảng tra cứu lỗi; riêng REST có V1_IDEMPOTENCY_KEY_REQUIRED và V1_CURSOR_INVALID.
  • Danh sách trả {object: "list", data, has_more, next_cursor, total}. Gửi lại nguyên next_cursor làm cursor để lấy trang kế. limit mặc định 20 và tối đa 100. Con trỏ không do chúng tôi cấp bị lỗi V1_CURSOR_INVALID (HTTP 400).
Nội dung lỗi
{
  "code": "V1_IDEMPOTENCY_KEY_REQUIRED",
  "message": "<text in the language of Accept-Language>",
  "retryable": false,
  "request_id": "<request id>"
}

Tài liệu OpenAPI

GET /v1/openapi.json trả tài liệu OpenAPI của API công khai và GET /v1/docs hiện các endpoint dưới dạng một trang. Cả hai đều không cần token và có thể được lưu đệm vài phút. Hợp đồng công khai là tài liệu này; các route mà chính ứng dụng web dùng không thuộc về nó.

Lấy tài liệu
curl -sS "$STUDIO_URL/v1/openapi.json"

Webhook

Webhook gửi một POST HTTPS có chữ ký tới máy chủ của bạn khi có việc hoàn tất, để script không phải hỏi liên tục.

  1. Quản trị viên của không gian làm việc đăng nhập ứng dụng web, mở Nhà phát triển rồi Webhook. Token API hoặc phiên MCP không quản lý được webhook: chúng nhận FORBIDDEN. Không có endpoint REST cho việc này.
  2. Thêm URL endpoint, mô tả tùy chọn tối đa 120 ký tự, và các sự kiện cần gửi, hoặc tất cả. Một không gian làm việc có tối đa 10 endpoint (WEBHOOK_LIMIT_REACHED, HTTP 409).
  3. Sao chép khóa ký, bắt đầu bằng whsec_. Khóa chỉ hiện một lần, khi bạn tạo endpoint hoặc xoay khóa. Sau đó chỉ hiện 4 ký tự cuối.
  4. Chọn Gửi thử để nhận sự kiện webhook.test, thường trong khoảng 30 giây. Gửi thử và gửi lại có giới hạn tốc độ: quá nhiều lần đang chờ sẽ trả WEBHOOK_RATE_LIMITED (HTTP 429, thử lại được); đợi vài giây rồi thử lại.
  • Xoay khóa: khóa trước vẫn tiếp tục ký thêm 24 giờ, nên bạn đổi khóa mà không mất sự kiện. Trong thời gian đó, header chữ ký mang một giá trị v1= cho mỗi khóa còn hiệu lực.
  • Một endpoint có thể bị tắt và xóa. Endpoint đã tắt không nhận gì (WEBHOOK_ENDPOINT_DISABLED, HTTP 409, khi bạn thử gửi thử tới nó).
  • Nhật ký gửi cho thấy mọi lần thử. Gửi lại sẽ gửi lại một lần gửi với cùng mã sự kiện, để máy chủ của bạn nhận ra bản trùng.

Sự kiện và header của yêu cầu

Các sự kiện webhook
Sự kiệnGửi khiTrường trong `data`
media_task.succeededMột tác vụ media, ví dụ một clip, đã xong.task_id, kind, state, billed_micros, currency, error_code, batch_id, row_index, url
media_task.failedMột tác vụ media thất bại.Các trường giống trên.
batch.completedMột lô clip đã kết thúc.batch_id, status, ready, needs_attention, cancelled, url
delivery.issuedMột bản giao đã được phát hành.delivery_id, project_id
webhook.testBạn chọn Gửi thử. Không thể đăng ký nhận sự kiện này.
Nội dung một sự kiện (created là thời điểm unix tính bằng giây)
{
  "api_version": "v1",
  "created": 1700000000,
  "data": {
    "batch_id": "<batch id>",
    "cancelled": 0,
    "needs_attention": 1,
    "ready": 9,
    "status": "completed",
    "url": "/v1/media-batches/<batch id>"
  },
  "id": "<event id>",
  "object": "event",
  "type": "batch.completed",
  "workspace_id": "<workspace id>"
}
Header của yêu cầu
HeaderGiá trị
Content-Typeapplication/json
User-AgentRPT-Webhooks/1
RPT-Signaturet=<unix seconds>,v1=<hex>
RPT-Event-IdMã sự kiện. Lần gửi lại giữ nguyên.
RPT-Event-TypeLoại sự kiện.
RPT-Delivery-IdLần gửi này.
RPT-Delivery-AttemptSố lần thử, bắt đầu từ 1.

Xác minh chữ ký

Chữ ký là HMAC-SHA256 dạng hex của {t}.{raw body}, với khóa là khóa ký. Luôn xác minh trước khi tin một yêu cầu:

  • Dùng nguyên các byte thô của nội dung, đúng như nhận được. Đừng phân tích rồi tuần tự hóa lại.
  • So sánh trong thời gian hằng số. Chấp nhận yêu cầu nếu bất kỳ giá trị v1 nào khớp.
  • Từ chối mốc thời gian lệch quá 300 giây so với đồng hồ của bạn, để yêu cầu cũ không bị phát lại.
  • Trả trạng thái 2xx ngay khi đã lưu sự kiện. Việc chậm làm sau.
Bộ nhận bằng Python (chỉ dùng thư viện chuẩn; hãy chạy sau HTTPS)
import hashlib
import hmac
import os
import time
from http.server import BaseHTTPRequestHandler, HTTPServer

SECRET = os.environ["WEBHOOK_SECRET"]


def valid(header, body):
    timestamp, candidates = None, []
    for part in (header or "").split(","):
        key, _, value = part.strip().partition("=")
        if key == "t":
            timestamp = value
        elif key == "v1":
            candidates.append(value)
    if timestamp is None or not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
        return False
    expected = hmac.new(SECRET.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
    return any(hmac.compare_digest(expected, candidate) for candidate in candidates)


class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
        ok = valid(self.headers.get("RPT-Signature"), body)
        self.send_response(204 if ok else 400)
        self.end_headers()


HTTPServer(("0.0.0.0", 8080), Handler).serve_forever()

Gửi, thử lại và đích an toàn

  • Mỗi lần thử chờ tối đa 8 giây. Mọi trạng thái khác 2xx đều tính là thất bại. Chuyển hướng (3xx) cũng là thất bại: chuyển hướng không bao giờ được đi theo.
  • Lần gửi thất bại được thử lại sau 30 giây, 2 phút, 10 phút, 30 phút, 1 giờ, 2 giờ, 4 giờ, 8 giờ và 8 giờ. Đó là chín lần thử lại trong khoảng 24 giờ. Sau đó lần gửi ở trạng thái failed. Trạng thái của lần gửi là queued, delivered hoặc failed.
  • URL endpoint phải là https, không có tên người dùng hay mật khẩu, không có fragment, và dài tối đa 2000 ký tự.
  • Máy chủ đích phải là một tên công khai. Địa chỉ IP, tên không có dấu chấm, hoặc tên kết thúc bằng .local, .internal, .localhost, .lan hay .home.arpa đều bị từ chối. Tên trỏ tới địa chỉ loopback, riêng tư, link-local hoặc địa chỉ dành riêng khác cũng vậy. Bộ gửi kết nối đúng địa chỉ đã kiểm tra, nên câu trả lời không thể đổi giữa lúc kiểm tra và lúc gọi.
  • URL bị từ chối cho lỗi WEBHOOK_URL_REFUSED (HTTP 422); details.reason là url_invalid, https_required, target_not_public hoặc dns_failed. Đích bị từ chối ở một lần gửi sau thì thất bại ngay, không thử lại.