Video Generation

Pomex provides an asynchronous video generation API powered by Seedance 2.0 and SkyReels. The workflow follows a task-based pattern: submit a generation request, then poll GET /v1/video/generations/{task_id} for results or provide a callback_url to be notified when Pomex observes a terminal state.

Asynchronous API — Video generation takes time. The Create endpoint returns immediately with a task object. In the common case the initial status is queued; if upstream already returns a richer snapshot, Pomex will persist and return that status instead. All models: poll the Get endpoint until status is terminal (succeeded, failed, or cancelled). You may also set callback_url; Seedance delivery is triggered by the upstream webhook, while SkyReels delivery is triggered by Pomex's background sweep when it detects completion or timeout.

Overview

Endpoint Method Description
/v1/video/generations POST Create a new video generation task
/v1/video/generations GET List your video generation tasks
/v1/video/generations/{task_id} GET Get a specific task (poll for status/result)
/v1/video/generations/{task_id} DELETE Delete (cancel) a video generation task
/v1/video/assets POST Create (upload) a new media asset for use as reference
/v1/video/assets/{asset_id} GET Get asset status and details

Available Models

Model ID Description Capabilities
byteplus/seedance-2.0 Seedance 2.0 — BytePlus's state-of-the-art video generation model Text-to-video, Image-to-video, Video-to-video, Audio-driven
skyreels/skyreels-v4-std SkyReels V4 Standard — high-quality video generation with standard mode Text-to-video, Image-to-video, Omni-video (multi-modal)
skyreels/skyreels-v4-fast SkyReels V4 Fast — faster generation with slightly reduced quality (no audio generation) Text-to-video, Image-to-video, Omni-video (multi-modal)
skyreels/skyreels-v3 SkyReels V3 — specialized video editing and transformation model Reference (multi-object), Extension, Cutshot, Restyling

Task Status Lifecycle

Status Description Terminal?
queued Task accepted, waiting for GPU resources No
running Video is being generated No
succeeded Generation complete — video URL available in content Yes
failed Generation failed — see error field for details Yes
cancelled Task was cancelled via DELETE Yes

Create Video Generation

POST /v1/video/generations

Submit a video generation task. The response returns immediately with a task object containing a unique id for polling.

Request Body Parameters

Parameter Type Required Description
model string Yes Model identifier. Options: "byteplus/seedance-2.0", "skyreels/skyreels-v4-std", "skyreels/skyreels-v4-fast", "skyreels/skyreels-v3"
content array Yes Array of content items describing the video to generate (text prompts, reference images/videos/audio). Must contain at least 1 item.
task_type string No Explicit task type for SkyReels models. If omitted, Pomex infers it from content. V4: "text-to-video", "image-to-video", "omni-video". V3: "reference", "extension", "cutshot", "restyling". Not used for Seedance models.
duration integer No Video duration in seconds. Minimum 4 seconds. Maximum depends on the generation mode and upstream configuration. Forwarded as-is when present.
ratio string No Aspect ratio. Supported values: "16:9", "9:16", "1:1". Forwarded to upstream after trimming whitespace.
resolution string No Output resolution. Common values are "720p" and "1080p". Provider-specific handling differs: SkyReels forwards the value to upstream, while Pomex billing estimates unknown SkyReels resolutions using the highest configured rate tier.
seed integer No Optional upstream seed value. Pomex stores nothing special here; it is passed through when present.
framespersecond integer No Optional FPS hint forwarded as-is to upstream. Note the JSON field name is exactly framespersecond.
generate_audio boolean No Optional upstream flag for generating audio. If omitted, Pomex does not inject a default; upstream behavior applies.
draft boolean No Draft mode flag (faster generation with lower quality). Only supported in image-to-video (i2v) mode. Not supported in text-to-video (t2v) — sending draft in t2v mode will be rejected by upstream.
service_tier string No Optional upstream service tier string, forwarded after trimming whitespace.
callback_url string No Customer webhook target stored by Pomex (HTTPS). When the task reaches a terminal state, Pomex POSTs the task JSON to this URL. Seedance delivery depends on the platform upstream webhook configured by VIDEO_WEBHOOK_BASE_URL; SkyReels has no upstream webhook, so Pomex's background sweep detects completion or timeout and then delivers the callback. This value is platform-only, not forwarded upstream as-is, and is not echoed in Get responses.
execution_expires_after integer No Requested execution timeout in seconds. If omitted, Pomex computes the effective timeout from provider config or falls back to 172800 seconds (48 hours).
metadata object No Arbitrary JSON metadata attached to the task. Returned in all subsequent responses.

Request Normalization Rules

Pomex does not reject every unsupported field combination. During create, it builds a sanitized upstream request body and drops unsupported fields or invalid content-item subfields where possible. A request is rejected only when required top-level fields are missing, or when sanitization leaves no valid content items.

Rule Behavior
Unsupported top-level fields Ignored for upstream submission. Example: custom fields such as watermark are dropped rather than forwarded.
text content role role is not forwarded on type="text" items.
Media item role Role handling is provider-specific. Seedance reference media uses reference_image, reference_video, and reference_audio. SkyReels uses task-specific roles such as first_frame, mid_frame, grid, extend, prefix_video, cut_type, and style_name; see the SkyReels sections below.
Wrong media field on item Extra fields such as text on a media item, or image_url on a video_url item, are dropped.
Invalid content items Items with unsupported type, missing required text, or missing required media URL are dropped. If all items are dropped, create returns 400.
callback_url The customer callback URL is stored by Pomex. For Seedance, if VIDEO_WEBHOOK_BASE_URL is configured, Pomex separately registers its own official upstream webhook endpoint at /v1/video/result with BytePlus. SkyReels upstream does not support webhooks; Pomex's background sweep polls and processes terminal or timed-out tasks, then delivers the customer callback.

Content Item Structure

Each element in the content array describes an input modality:

Field Type Description
type string Required. One of: "text", "image_url", "video_url", "audio_url"
role string Optional role for media or special text items. Accepted values depend on the provider and task type. Seedance reference roles are "reference_image", "reference_video", and "reference_audio"; SkyReels roles are documented in the SkyReels model sections below.
text string Text content (required when type is "text"). This is your generation prompt.
image_url object Image reference (required when type is "image_url"). Contains {"url": "..."}
video_url object Video reference (required when type is "video_url"). Contains {"url": "..."}
audio_url object Audio reference (required when type is "audio_url"). Contains {"url": "..."}
tag string Tag identifier for SkyReels models. Required for mid_frame images in I2V and all media in omni-video. If a non-empty tag does not start with @, Pomex prefixes it before forwarding; missing required tags return 400.
time_stamp number Timestamp in seconds for SkyReels mid_frame images in I2V mode. Converted to integer seconds for upstream.

Generation Modes

These are common Seedance request shapes supported by the current request sanitizer and upstream mapping. SkyReels uses additional task-specific roles and request shapes described in the SkyReels sections below.

Mode Content Configuration Description
Text-to-Video [{type:"text", text:"..."}] Generate video from a text prompt alone.
Image-to-Video [{type:"text", text:"..."}, {type:"image_url", role:"reference_image", image_url:{url:"..."}}] Animate a reference image with a text prompt. For Seedance, the media role is optional but only reference_image is preserved if provided.
Video-to-Video [{type:"text", text:"..."}, {type:"video_url", role:"reference_video", video_url:{url:"..."}}] Transform or extend a reference video. Only reference_video is preserved if a role is provided.
Audio-driven [{type:"text", text:"..."}, {type:"image_url", role:"reference_image", ...}, {type:"audio_url", role:"reference_audio", audio_url:{url:"..."}}] Generate video synchronized to reference audio. Audio cannot be the only reference input — you must also include a reference_image or reference_video alongside the audio reference.

Parameter Constraints

Constraint Details
duration Minimum 4 seconds. Maximum depends on generation mode (typically 5–10s for i2v, up to 15s for t2v).
ratio Supported: "16:9", "9:16", "1:1".
resolution Common values are "720p" and "1080p". SkyReels forwards other values to upstream, but unknown SkyReels resolutions are estimated for billing using the highest configured rate tier.
draft Only supported in image-to-video (i2v) mode. Sending draft in text-to-video (t2v) will be rejected.
reference_audio For Seedance audio-driven requests, audio cannot be the only reference input and must be combined with reference_image or reference_video. SkyReels omni-video audio must be associated with an image tag.

Example: Text-to-Video

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "byteplus/seedance-2.0",
    "content": [
      {
        "type": "text",
        "text": "A golden retriever running through a field of sunflowers at sunset, cinematic 4K, slow motion"
      }
    ],
    "duration": 10,
    "ratio": "16:9",
    "resolution": "1080p"
  }'
import requests

resp = requests.post(
    "https://api.pomex.ai/v1/video/generations",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "byteplus/seedance-2.0",
        "content": [
            {
                "type": "text",
                "text": "A golden retriever running through a field of sunflowers at sunset, cinematic 4K, slow motion"
            }
        ],
        "duration": 10,
        "ratio": "16:9",
        "resolution": "1080p",
    },
)

task = resp.json()
print(task["id"], task["status"])
# → "task_abc123..." "queued"

Response (200 OK)

{
  "id": "task_01JXN4KQWER5678ABCDEFGH",
  "object": "video.generation.task",
  "created": 1748160000,
  "model": "byteplus/seedance-2.0",
  "status": "queued",
  "metadata": {}
}

Example: Image-to-Video

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "byteplus/seedance-2.0",
    "content": [
      {
        "type": "text",
        "text": "The character slowly turns their head and smiles at the camera"
      },
      {
        "type": "image_url",
        "role": "reference_image",
        "image_url": {
          "url": "https://example.com/portrait.jpg"
        }
      }
    ],
    "duration": 5,
    "ratio": "9:16",
    "resolution": "1080p"
  }'

Example: With Audio and Callback

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "byteplus/seedance-2.0",
    "content": [
      {
        "type": "text",
        "text": "A musician playing piano in a dimly lit jazz club"
      },
      {
        "type": "image_url",
        "role": "reference_image",
        "image_url": {
          "url": "https://example.com/pianist-photo.jpg"
        }
      },
      {
        "type": "audio_url",
        "role": "reference_audio",
        "audio_url": {
          "url": "https://example.com/jazz-piano.mp3"
        }
      }
    ],
    "generate_audio": true,
    "duration": 15,
    "ratio": "16:9",
    "callback_url": "https://myapp.example.com/webhooks/video-done",
    "metadata": {"project": "music-video", "scene": 3}
  }'

Get Video Generation

GET /v1/video/generations/{task_id}

Retrieve the current status and result of a video generation task. If the task is still non-terminal, Pomex synchronizes the latest upstream snapshot before returning. Poll this endpoint until status reaches a terminal state (succeeded, failed, or cancelled).

Path Parameters

Parameter Type Description
task_id string The unique task identifier returned by the Create endpoint.

Example Request

curl https://api.pomex.ai/v1/video/generations/task_01JXN4KQWER5678ABCDEFGH \
  -H "Authorization: Bearer $POMEX_API_KEY"
import time
import requests

task_id = "task_01JXN4KQWER5678ABCDEFGH"
headers = {"Authorization": "Bearer YOUR_API_KEY"}

# Polling loop
while True:
    resp = requests.get(
        f"https://api.pomex.ai/v1/video/generations/{task_id}",
        headers=headers,
    )
    task = resp.json()
    print(f"Status: {task['status']}")

    if task["status"] in ("succeeded", "failed", "cancelled"):
        break
    time.sleep(5)  # poll every 5 seconds

# On success, content contains the video URL
if task["status"] == "succeeded":
    print("Video URL:", task["content"]["video_url"])
elif task["status"] == "failed":
    print("Failed:", task["error"])

Note: The content.video_url is a pre-signed URL with a time-limited expiry (typically 24 hours). Download the video promptly or poll the Get endpoint again to obtain a fresh URL.

Response: Running

{
  "id": "task_01JXN4KQWER5678ABCDEFGH",
  "object": "video.generation.task",
  "created": 1748160000,
  "model": "byteplus/seedance-2.0",
  "status": "running",
  "updated_at": 1748160012
}

Response: Succeeded

{
  "id": "cgt-20260526115001-ldvq4",
  "object": "video.generation.task",
  "created": 1779767402,
  "model": "byteplus/seedance-2.0",
  "status": "succeeded",
  "updated_at": 1779767585,
  "completed_at": 1779767585,
  "content": {
    "video_url": "https://ark-acg-ap-southeast-1.tos-ap-southeast-1.volces.com/dreamina-seedance-2-0/example.mp4?X-Tos-Algorithm=TOS4-HMAC-SHA256&..."
  },
  "metadata": {}
}

Note: The content field contains upstream-defined payload. For succeeded tasks, it typically has a video_url field with a pre-signed download URL. The URL is time-limited (usually 24 hours) — download promptly or use the Get endpoint to obtain a fresh URL.

Response: Failed

{
  "id": "task_01JXN4KQWER5678ABCDEFGH",
  "object": "video.generation.task",
  "created": 1748160000,
  "model": "byteplus/seedance-2.0",
  "status": "failed",
  "updated_at": 1748160045,
  "completed_at": 1748160045,
  "error": {
    "code": "content_policy_violation",
    "message": "The prompt was rejected due to content policy.",
    "type": "video_generation_error",
    "param": null
  }
}

List Video Generations

GET /v1/video/generations

List all non-deleted video generation tasks for the authenticated API key. This endpoint reads from Pomex storage only and does not synchronize with upstream. Results are ordered by created_at DESC, task_id DESC and support cursor-based pagination.

Query Parameters

Parameter Type Default Description
limit integer 20 Number of tasks to return. Omitted or 0 becomes 20. Values above 100 are capped at 100. Negative or non-integer values return 400.
cursor string Opaque pagination cursor from a previous response's next_cursor.

Example Request

curl "https://api.pomex.ai/v1/video/generations?limit=5" \
  -H "Authorization: Bearer $POMEX_API_KEY"

Response

{
  "object": "list",
  "data": [
    {
      "id": "task_01JXN4KQWER5678ABCDEFGH",
      "object": "video.generation.task",
      "created": 1748160000,
  "model": "byteplus/seedance-2.0",
  "status": "succeeded",
  "completed_at": 1748160090
    },
    {
      "id": "task_01JXN3ABCDEF1234567890",
      "object": "video.generation.task",
      "created": 1748159000,
      "model": "byteplus/seedance-2.0",
      "status": "running"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wNS0yNVQxMDowMDowMFoifQ"
}

Delete Video Generation

DELETE /v1/video/generations/{task_id}

Delete a video generation task. Pomex first calls upstream DELETE, then soft-deletes the local task row and returns a compact delete response.

If upstream returns a final snapshot during delete, Pomex will merge that snapshot and attempt terminal billing settlement before soft deletion.

Path Parameters

Parameter Type Description
task_id string The task identifier to delete.

Example Request

curl -X DELETE https://api.pomex.ai/v1/video/generations/task_01JXN4KQWER5678ABCDEFGH \
  -H "Authorization: Bearer $POMEX_API_KEY"

Response (200 OK)

{
  "id": "task_01JXN4KQWER5678ABCDEFGH",
  "object": "video.generation.task",
  "deleted": true
}

Webhook Callback

If you provide a callback_url in the Create request, Pomex stores it and POSTs the task JSON to that URL when the task reaches a terminal state. For Seedance, delivery is triggered after Pomex receives the upstream completion webhook from BytePlus (see VIDEO_WEBHOOK_BASE_URL below). For SkyReels, the upstream does not support webhooks; Pomex relies on its background sweep to poll task status, handle timeouts, and trigger the customer callback after it observes a terminal state. The request body matches the Get endpoint response.

SkyReels: upstream does not support webhooks. Pomex still supports customer callback_url by running a background sweep that polls SkyReels tasks and handles timeouts; when the sweep observes a terminal state, Pomex delivers the callback. Poll GET /v1/video/generations/{task_id} (recommended every ~10s) as a client-side fallback.

Platform requirement: Seedance callbacks require VIDEO_WEBHOOK_BASE_URL to be set on the Pomex deployment (e.g. https://api.pomex.ai). When empty, Create does not register an official upstream webhook and Seedance customer callbacks will not fire. SkyReels callbacks are driven by the Pomex background sweep instead of an upstream webhook.

Delivery rules: only HTTPS callback URLs are delivered. The current default retry config is 3 attempts total (initial try plus 2 retries) with backoff delays of 1s and 3s. Network errors and 5xx responses are retried; 4xx responses are not retried. callback_url is stored but not returned in Get responses; use metadata for correlation IDs.

Callback Request Body

POST https://yourapp.example.com/webhooks/video-done
Content-Type: application/json

{
  "id": "task_01JXN4KQWER5678ABCDEFGH",
  "object": "video.generation.task",
  "created": 1748160000,
  "model": "byteplus/seedance-2.0",
  "status": "succeeded",
  "completed_at": 1748160090,
  "content": {
    "video_url": "https://ark-acg-ap-southeast-1.tos-ap-southeast-1.volces.com/dreamina-seedance-2-0/example.mp4?X-Tos-Algorithm=TOS4-HMAC-SHA256&..."
  },
  "metadata": {"project": "music-video", "scene": 3}
}

Complete Workflow Example

Here's a full Python example that creates a video, polls for completion, and downloads the result:

import time
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.pomex.ai"
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

# Step 1: Create the video generation task
create_resp = requests.post(
    f"{BASE_URL}/v1/video/generations",
    headers=headers,
    json={
        "model": "byteplus/seedance-2.0",
        "content": [
            {"type": "text", "text": "A serene ocean wave crashing on a rocky shore at golden hour, 4K cinematic"},
            {
                "type": "image_url",
                "role": "reference_image",
                "image_url": {"url": "https://example.com/beach-reference.jpg"},
            },
        ],
        "duration": 10,
        "ratio": "16:9",
        "resolution": "1080p",
        "generate_audio": True,
    },
)
create_resp.raise_for_status()
task = create_resp.json()
task_id = task["id"]
print(f"Task created: {task_id} (status: {task['status']})")

# Step 2: Poll until terminal state
while task["status"] not in ("succeeded", "failed", "cancelled"):
    time.sleep(5)
    poll_resp = requests.get(f"{BASE_URL}/v1/video/generations/{task_id}", headers=headers)
    poll_resp.raise_for_status()
    task = poll_resp.json()
    print(f"  Status: {task['status']}")

# Step 3: Handle result
if task["status"] == "succeeded":
    video_url = task["content"]["video_url"]
    print(f"Video URL: {video_url}")

    # Download the video (URL is time-limited, typically 24h)
    video_data = requests.get(video_url).content
    with open("output.mp4", "wb") as f:
        f.write(video_data)
    print("Saved to output.mp4")

elif task["status"] == "failed":
    print(f"Generation failed: {task['error']['message']}")

elif task["status"] == "cancelled":
    print("Task was cancelled")

Error Responses

Error responses use the same top-level OpenAI-style error envelope as the rest of Pomex. The exact type string varies by code path, so the table below focuses on status and trigger conditions that are confirmed in the implementation.

{
  "error": {
    "message": "content must contain at least one item",
    "type": "invalid_request_error",
    "param": null,
    "code": null
  }
}
HTTP Status Cause
400 Invalid request body, missing model, empty content, invalid list cursor, invalid list limit, missing task_id, or sanitized request with no valid content items remaining.
401 Missing or invalid API key
402 Insufficient credit balance for prepaid accounts
404 Unsupported model on create, or task_id not found for get/delete
413 Request body too large
429 Rate limit exceeded during create
503 Store/upstream not configured, billing unavailable, persistence failure, or other service-side dependency failure

SkyReels Models

SkyReels models use the same /v1/video/generations endpoints but with additional parameters and different content structure conventions. The key difference is the task_type parameter which determines the generation operation.

Task Type Inference — The task_type field is optional. If omitted, Pomex automatically infers it from the content array structure. You can also set it explicitly to override the inference logic.

Polling recommended — SkyReels has no upstream webhook. Pomex can deliver customer callback_url after its background sweep detects completion or timeout, but clients should still poll GET /v1/video/generations/{task_id} until status is terminal as a fallback.

Delete Not Supported — SkyReels upstream does not support the DELETE operation. Attempting to delete a SkyReels task will return 400 with "SkyReels video tasks cannot be deleted".

SkyReels V4 Models

V4 models (skyreels/skyreels-v4-std and skyreels/skyreels-v4-fast) support three task types:

Task Type Inference Rule Description
text-to-video Content has only text items Generate video from text prompt alone
image-to-video Content includes image_url item(s) Generate video from reference images with keyframe control
omni-video Content includes video_url or audio_url items Multi-modal video generation with image, video, and audio references

SkyReels V4 Additional Parameters

Parameter Type Required Description
task_type string No Explicitly set the task type. V4 accepts: "text-to-video", "image-to-video", "omni-video". If omitted, inferred from content.
duration integer No Video duration in seconds.
ratio string No Aspect ratio (e.g. "16:9", "9:16", "1:1"). Mapped to upstream aspect_ratio.
resolution string No Output resolution (e.g. "720p", "1080p").
generate_audio boolean No Enable audio generation. Not supported for skyreels-v4-fast — will be rejected if set to true.

V4 Text-to-Video

Generate video purely from a text prompt. Multiple text items are merged with newlines.

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v4-std",
    "content": [
      {
        "type": "text",
        "text": "A futuristic city at night with neon lights reflecting off wet streets, cinematic drone shot"
      }
    ],
    "duration": 10,
    "ratio": "16:9",
    "generate_audio": true
  }'
import requests

resp = requests.post(
    "https://api.pomex.ai/v1/video/generations",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "skyreels/skyreels-v4-std",
        "content": [
            {
                "type": "text",
                "text": "A futuristic city at night with neon lights reflecting off wet streets, cinematic drone shot"
            }
        ],
        "duration": 10,
        "ratio": "16:9",
        "generate_audio": True,
    },
)

task = resp.json()
print(task["id"], task["status"])

Response (200 OK)

{
  "id": "task_01SKYREELS_T2V_EXAMPLE",
  "object": "video.generation.task",
  "created": 1749820000,
  "model": "skyreels/skyreels-v4-std",
  "status": "queued",
  "metadata": {}
}

V4 Image-to-Video

Animate reference images into video. SkyReels I2V supports keyframe control with specific image roles:

Image Role Required Description
first_frame At least one frame required Starting frame of the video. Default role when no role is specified.
end_frame No Target ending frame of the video.
mid_frame No Intermediate keyframe. Requires tag field. Supports optional time_stamp (seconds, integer).

Keyframe control: You can specify first_frame, end_frame, and multiple mid_frame images to guide the video generation trajectory. At least one of first_frame, end_frame, or mid_frame must be present.

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v4-std",
    "content": [
      {
        "type": "text",
        "text": "A woman walking through a garden, camera follows from behind"
      },
      {
        "type": "image_url",
        "role": "first_frame",
        "image_url": {
          "url": "https://example.com/start-frame.jpg"
        }
      },
      {
        "type": "image_url",
        "role": "end_frame",
        "image_url": {
          "url": "https://example.com/end-frame.jpg"
        }
      }
    ],
    "duration": 8,
    "ratio": "16:9"
  }'
With Mid-Frame Keypoints
curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v4-std",
    "content": [
      {
        "type": "text",
        "text": "A dancer performing a graceful spin"
      },
      {
        "type": "image_url",
        "role": "first_frame",
        "image_url": {
          "url": "https://example.com/dance-start.jpg"
        }
      },
      {
        "type": "image_url",
        "role": "mid_frame",
        "tag": "pose_peak",
        "time_stamp": 3,
        "image_url": {
          "url": "https://example.com/dance-peak.jpg"
        }
      },
      {
        "type": "image_url",
        "role": "end_frame",
        "image_url": {
          "url": "https://example.com/dance-end.jpg"
        }
      }
    ],
    "duration": 6,
    "ratio": "9:16"
  }'

V4 Omni-Video

Multi-modal video generation combining text prompts with image, video, and audio references. Automatically inferred when content contains video_url or audio_url items.

Tag required: All media references in omni-video mode require a tag field (prefixed with @, auto-added if missing). Tags are used to associate related references (e.g., linking audio to a specific image reference).

Content Item Roles for Omni-Video
Type Role Description
image_url image (default) or grid Reference image(s). grid type requires exactly one image per tag. Multiple images allowed for image type.
video_url reference (default) or extend Reference video. Only one video reference is supported. extend type cannot be combined with image references.
audio_url Audio reference associated with an image tag. Only supported for image-type references.
curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v4-std",
    "content": [
      {
        "type": "text",
        "text": "A character speaking with natural lip movements in a cozy room"
      },
      {
        "type": "image_url",
        "role": "image",
        "tag": "character",
        "image_url": {
          "url": "https://example.com/character-portrait.jpg"
        }
      },
      {
        "type": "audio_url",
        "tag": "character",
        "audio_url": {
          "url": "https://example.com/speech.mp3"
        }
      }
    ],
    "duration": 10,
    "ratio": "16:9",
    "generate_audio": true
  }'
Omni-Video with Video Extension
curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v4-std",
    "content": [
      {
        "type": "text",
        "text": "Continue the scene as the camera slowly pulls back to reveal the full landscape"
      },
      {
        "type": "video_url",
        "role": "extend",
        "tag": "source",
        "video_url": {
          "url": "https://example.com/original-clip.mp4"
        }
      }
    ],
    "duration": 8,
    "ratio": "16:9"
  }'

V4 Fast Mode

The skyreels/skyreels-v4-fast model provides faster generation with the same task types but does not support generate_audio. Setting generate_audio: true with a fast model will result in an error.

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v4-fast",
    "content": [
      {
        "type": "text",
        "text": "A quick preview of ocean waves at sunset"
      }
    ],
    "duration": 5,
    "ratio": "16:9"
  }'

SkyReels V3 Model

The skyreels/skyreels-v3 model specializes in video editing and transformation operations. It supports four task types:

Task Type Inference Rule Description
reference Content has image_url items (no video) Multi-object video generation from 1–4 reference images
extension Content has video_url with role="prefix_video" Extend an existing video clip
cutshot Content has prefix_video + text with role="cut_type" Generate a camera cut/transition from a video
restyling Content has video_url + text with role="style_name" Apply a visual style to an existing video

V3 Reference (Multi-Object)

Generate a video featuring 1 to 4 reference objects/characters from images. Requires at least one text prompt and 1–4 reference images.

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v3",
    "task_type": "reference",
    "content": [
      {
        "type": "text",
        "text": "Two characters having a conversation at a cafe table"
      },
      {
        "type": "image_url",
        "image_url": {
          "url": "https://example.com/character-a.jpg"
        }
      },
      {
        "type": "image_url",
        "image_url": {
          "url": "https://example.com/character-b.jpg"
        }
      }
    ],
    "duration": 8,
    "ratio": "16:9"
  }'

Reference limit: The reference task type supports 1 to 4 reference images. Providing 0 or more than 4 images will return an error.

V3 Extension

Extend an existing video clip by continuing it with AI-generated content. Requires a video with role="prefix_video" and a text prompt.

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v3",
    "task_type": "extension",
    "content": [
      {
        "type": "text",
        "text": "The character continues walking and enters the building"
      },
      {
        "type": "video_url",
        "role": "prefix_video",
        "video_url": {
          "url": "https://example.com/original-clip.mp4"
        }
      }
    ],
    "duration": 5
  }'

V3 Cutshot

Generate a camera cut/transition from a source video. Requires a prefix_video and a cut_type text item specifying the type of camera transition.

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v3",
    "task_type": "cutshot",
    "content": [
      {
        "type": "text",
        "text": "A dramatic reveal of the cityscape"
      },
      {
        "type": "text",
        "role": "cut_type",
        "text": "zoom_out"
      },
      {
        "type": "video_url",
        "role": "prefix_video",
        "video_url": {
          "url": "https://example.com/scene-clip.mp4"
        }
      }
    ],
    "duration": 5
  }'

V3 Restyling (Style Transfer)

Apply a visual style transformation to an existing video. Requires a source video_url and a text item with role="style_name" specifying the target style.

curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "skyreels/skyreels-v3",
    "task_type": "restyling",
    "content": [
      {
        "type": "text",
        "role": "style_name",
        "text": "anime"
      },
      {
        "type": "video_url",
        "video_url": {
          "url": "https://example.com/real-footage.mp4"
        }
      }
    ]
  }'

SkyReels Response Format

SkyReels tasks use the same response structure as Seedance tasks. The Get endpoint returns a unified task object:

Response: Succeeded

{
  "id": "task_01SKYREELS_EXAMPLE",
  "object": "video.generation.task",
  "created": 1749820000,
  "model": "skyreels/skyreels-v4-std",
  "status": "succeeded",
  "updated_at": 1749820180,
  "completed_at": 1749820180,
  "content": {
    "video_url": "https://cdn.skyreels.ai/output/example-video.mp4?token=..."
  },
  "metadata": {}
}

SkyReels Status Mapping

Pomex normalizes upstream SkyReels statuses to the standard lifecycle:

SkyReels Upstream Pomex Status
submitted / pending / ok queued
running / unknown running
success succeeded
failed failed

SkyReels-Specific Constraints

Constraint Details
generate_audio + fast model generate_audio: true is not supported for skyreels/skyreels-v4-fast. Will return 400.
V3 task_type on V4 model V3 task types (reference, extension, cutshot, restyling) cannot be used with V4 models. Returns 400.
V4 task_type on V3 model V4 task types (text-to-video, image-to-video, omni-video) cannot be used with V3 models. Returns 400.
Omni ref_videos extend + ref_images Video extend type cannot be combined with image references in omni-video. Returns 400.
Reference image count V3 reference requires 1 to 4 images. Outside this range returns 400.
DELETE not supported SkyReels tasks cannot be deleted. Returns 400.

Video Assets

The Video Assets API allows you to upload media files (images, videos, audio) to the asset library for use as references in video generation. Assets are uploaded via URL, processed and moderated by upstream, then become available for use in generation requests.

Endpoint Method Description
/v1/video/assets POST Create (upload) a new asset
/v1/video/assets/{asset_id} GET Get asset status and details

Asset Status Lifecycle

Status Description
processing Asset uploaded and being processed/moderated by upstream
active Asset is ready for use in video generation requests
failed Processing or moderation failed — see error field for details

Create Asset

POST /v1/video/assets

Upload a media file by providing its HTTPS URL. The asset will be processed and moderated by the upstream service. The response returns immediately with the asset ID and a processing status.

Request Body Parameters

Parameter Type Required Description
url string Yes HTTPS URL of the media file to upload. Must be a valid https:// URL.
asset_type string Yes Type of the asset. Must be one of: "Image", "Video", "Audio" (case-sensitive).
name string No Optional human-readable name for the asset. Maximum 64 characters.

Example Request

curl https://api.pomex.ai/v1/video/assets \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/my-reference-image.jpg",
    "asset_type": "Image",
    "name": "Beach portrait reference"
  }'
import requests

resp = requests.post(
    "https://api.pomex.ai/v1/video/assets",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "url": "https://example.com/my-reference-image.jpg",
        "asset_type": "Image",
        "name": "Beach portrait reference",
    },
)

asset = resp.json()
print(asset["id"], asset["status"])
# → "asset_abc123..." "processing"

Response (200 OK)

{
  "id": "asset_01JXN5ABC1234567890DEF",
  "object": "video.asset",
  "status": "processing"
}

Get Asset

GET /v1/video/assets/{asset_id}

Retrieve the current status and details of an asset. Poll this endpoint to check when an asset becomes active and ready for use in video generation requests.

Path Parameters

Parameter Type Description
asset_id string The unique asset identifier returned by the Create endpoint.

Example Request

curl https://api.pomex.ai/v1/video/assets/asset_01JXN5ABC1234567890DEF \
  -H "Authorization: Bearer $POMEX_API_KEY"

Response: Processing

{
  "id": "asset_01JXN5ABC1234567890DEF",
  "object": "video.asset",
  "name": "Beach portrait reference",
  "asset_type": "Image",
  "status": "processing",
  "created_at": "2026-05-25T10:00:00Z",
  "updated_at": "2026-05-25T10:00:00Z"
}

Response: Active

{
  "id": "asset_01JXN5ABC1234567890DEF",
  "object": "video.asset",
  "name": "Beach portrait reference",
  "url": "https://cdn.example.com/assets/processed_abc123.jpg",
  "asset_type": "Image",
  "status": "active",
  "created_at": "2026-05-25T10:00:00Z",
  "updated_at": "2026-05-25T10:00:15Z"
}

Response: Failed

{
  "id": "asset_01JXN5ABC1234567890DEF",
  "object": "video.asset",
  "name": "Beach portrait reference",
  "asset_type": "Image",
  "status": "failed",
  "error": {
    "code": "moderation_rejected",
    "message": "Asset rejected during content moderation"
  },
  "created_at": "2026-05-25T10:00:00Z",
  "updated_at": "2026-05-25T10:00:20Z"
}

Asset Error Responses

HTTP Status Cause
400 Missing or invalid url (must be HTTPS), missing or invalid asset_type (must be Image/Video/Audio), name exceeds 64 characters, missing asset_id in path
401 Missing or invalid API key
404 Asset not found (wrong asset_id or asset belongs to a different organization)
413 Request body too large
503 Asset service unavailable, organization asset library not configured, admin credentials not configured, upstream failure, or persistence failure

Using Assets in Video Generation

Once an asset reaches active status, use the asset://{asset_id} protocol URL in your video generation request's media fields. The gateway resolves the asset reference automatically:

# Step 1: Create an image asset
curl https://api.pomex.ai/v1/video/assets \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/my-portrait.jpg",
    "asset_type": "Image",
    "name": "Portrait reference"
  }'
# → {"id":"asset-20260524233646-v76gs","object":"video.asset","status":"processing"}

# Step 2: Poll until active
curl https://api.pomex.ai/v1/video/assets/asset-20260524233646-v76gs \
  -H "Authorization: Bearer $POMEX_API_KEY"
# → {"id":"asset-20260524233646-v76gs","object":"video.asset","status":"active",...}

# Step 3: Use asset:// protocol URL in video generation
curl https://api.pomex.ai/v1/video/generations \
  -H "Authorization: Bearer $POMEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "byteplus/seedance-2.0",
    "content": [
      {
        "type": "text",
        "text": "The person slowly turns their head and smiles warmly at the camera"
      },
      {
        "type": "image_url",
        "role": "reference_image",
        "image_url": {
          "url": "asset://asset-20260524233646-v76gs"
        }
      }
    ],
    "duration": 5,
    "ratio": "9:16"
  }'
import time
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.pomex.ai"
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

# Step 1: Upload an image asset
asset_resp = requests.post(
    f"{BASE_URL}/v1/video/assets",
    headers=headers,
    json={
        "url": "https://example.com/my-portrait.jpg",
        "asset_type": "Image",
        "name": "Portrait reference",
    },
)
asset_resp.raise_for_status()
asset_id = asset_resp.json()["id"]
print(f"Asset created: {asset_id}")

# Step 2: Poll until the asset is active
while True:
    get_resp = requests.get(f"{BASE_URL}/v1/video/assets/{asset_id}", headers=headers)
    get_resp.raise_for_status()
    asset = get_resp.json()
    print(f"  Asset status: {asset['status']}")
    if asset["status"] == "active":
        break
    elif asset["status"] == "failed":
        raise RuntimeError(f"Asset failed: {asset.get('error', {}).get('message')}")
    time.sleep(3)

print(f"Asset ready: {asset_id}")

# Step 3: Use asset:// protocol URL in video generation
gen_resp = requests.post(
    f"{BASE_URL}/v1/video/generations",
    headers=headers,
    json={
        "model": "byteplus/seedance-2.0",
        "content": [
            {
                "type": "text",
                "text": "The person slowly turns their head and smiles warmly at the camera",
            },
            {
                "type": "image_url",
                "role": "reference_image",
                "image_url": {"url": f"asset://{asset_id}"},
            },
        ],
        "duration": 5,
        "ratio": "9:16",
    },
)
gen_resp.raise_for_status()
task = gen_resp.json()
print(f"Video task created: {task['id']} (status: {task['status']})")

# Step 4: Poll video generation until complete
while task["status"] not in ("succeeded", "failed", "cancelled"):
    time.sleep(5)
    poll_resp = requests.get(f"{BASE_URL}/v1/video/generations/{task['id']}", headers=headers)
    poll_resp.raise_for_status()
    task = poll_resp.json()
    print(f"  Video status: {task['status']}")

if task["status"] == "succeeded":
    print("Video URL:", task["content"]["video_url"])

Key point: Use the asset://{asset_id} protocol URL to reference uploaded assets in video generation requests. The gateway resolves asset references to the underlying processed media automatically. You can also use direct HTTPS URLs to publicly accessible media without creating assets first.


Rate Limits & Billing

  • Rate limits are enforced during create. Pomex estimates token usage and checks QoS limits before submitting the upstream task.
  • Prepaid credit is reserved during create when the organization uses prepaid billing. If upstream submission or persistence fails, Pomex rolls the reservation back.
  • Terminal settlement happens when a terminal snapshot is observed via Get, webhook, or delete-time merge.
  • Daily quota hooks are executed around create and terminal settlement when quota management is enabled for the deployment.
  • Timeouts are part of billing and lifecycle: if a queued/running task passes its effective timeout, Pomex can mark it failed with error.code = "video_timeout".