OpenAI Videos API

The Poe API supports the OpenAI Video Generation API format, enabling AI-powered video creation through the same OpenAI SDK you already know. Just point it at Poe.

Key capabilities:

  • Text-to-video and image-to-video generation
  • Video remix (re-style an existing video with a new prompt)
  • Video extension (continue a completed video)
  • Access video models (Sora, Veo) through a single Poe API key
  • Asynchronous workflow with polling

Video generation is asynchronous. You submit a request, poll for completion, then download the result.

Quick Start

Create a video, poll until it completes, and download the result:

# pip install openai
import os, time, openai

client = openai.OpenAI(
    api_key=os.getenv("POE_API_KEY"),  # https://poe.com/api/keys
    base_url="https://api.poe.com/v1",
)

# Submit video generation request
video = client.videos.create(
    model="Sora-2",  # Poe bot name
    prompt="A golden retriever running through a sunflower field at sunset",
    seconds=8,
    size="1280x720",
)

# Poll until complete
while video.status in ("queued", "in_progress"):
    time.sleep(5)
    video = client.videos.retrieve(video_id=video.id)

print(f"Video completed: {video.id}")

# Download the video
content = client.videos.download_content(video_id=video.id)
with open("output.mp4", "wb") as f:
    f.write(content.content)

print("Saved to output.mp4")

Or use the convenience helper that combines create + poll:

# Blocks until video is complete
video = client.videos.create_and_poll(
    model="Sora-2",
    prompt="A golden retriever running through a sunflower field at sunset",
    seconds=8,
    size="1280x720",
)

print(f"Video completed: {video.id}")

content = client.videos.download_content(video_id=video.id)
with open("output.mp4", "wb") as f:
    f.write(content.content)
# 1. Create the video
curl "https://api.poe.com/v1/videos" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $POE_API_KEY" \
    -d '{
        "model": "Sora-2",
        "prompt": "A golden retriever running through a sunflower field at sunset",
        "seconds": 8,
        "size": "1280x720"
    }'

# 2. Poll for completion (replace VIDEO_ID with the id from step 1)
curl "https://api.poe.com/v1/videos/VIDEO_ID" \
    -H "Authorization: Bearer $POE_API_KEY"

# 3. Download the video (once status is "completed")
curl "https://api.poe.com/v1/videos/VIDEO_ID/content" \
    -H "Authorization: Bearer $POE_API_KEY" \
    --output output.mp4

Image-to-Video

Generate a video from a reference image:

import os, openai

client = openai.OpenAI(
    api_key=os.getenv("POE_API_KEY"),
    base_url="https://api.poe.com/v1",
)

video = client.videos.create_and_poll(
    model="Sora-2",
    prompt="The dog starts running and jumps over a log",
    input_reference=open("image.jpg", "rb"),
)

content = client.videos.download_content(video_id=video.id)
with open("output.mp4", "wb") as f:
    f.write(content.content)
curl "https://api.poe.com/v1/videos" \
    -H "Authorization: Bearer $POE_API_KEY" \
    -F "model=Sora-2" \
    -F "prompt=The dog starts running and jumps over a log" \
    -F "[email protected]"

Remix

Re-style an existing video with a new prompt:

import os, time, openai

client = openai.OpenAI(
    api_key=os.getenv("POE_API_KEY"),
    base_url="https://api.poe.com/v1",
)

remix = client.videos.remix(
    video_id=video.id,
    prompt="Transform into an anime-style animation",
)

# Poll until complete
while remix.status in ("queued", "in_progress"):
    time.sleep(5)
    remix = client.videos.retrieve(video_id=remix.id)

content = client.videos.download_content(video_id=remix.id)
with open("remix.mp4", "wb") as f:
    f.write(content.content)
# Replace VIDEO_ID with the source video's id
curl "https://api.poe.com/v1/videos/VIDEO_ID/remix" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $POE_API_KEY" \
    -d '{
        "prompt": "Transform into an anime-style animation"
    }'

Note: The model is inherited from the source video. You do not need to specify a model parameter for remix requests.

Extend a Video

Continue a completed video with additional content:

import os, time, openai

client = openai.OpenAI(
    api_key=os.getenv("POE_API_KEY"),
    base_url="https://api.poe.com/v1",
)

extension = client.post(
    "/videos/extensions",
    body={
        "video": {"id": video.id},
        "prompt": "The dog continues running and leaps into a lake",
        "seconds": 8,
    },
    cast_to=openai.types.video.Video,
)

# Poll until complete
while extension.status in ("queued", "in_progress"):
    time.sleep(5)
    extension = client.videos.retrieve(video_id=extension.id)

content = client.videos.download_content(video_id=extension.id)
with open("extended.mp4", "wb") as f:
    f.write(content.content)
curl "https://api.poe.com/v1/videos/extensions" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $POE_API_KEY" \
    -d '{
        "video": {"id": "VIDEO_ID"},
        "prompt": "The dog continues running and leaps into a lake",
        "seconds": 8
    }'

Note: The source video must be in completed status. The model is inherited from the source video. The seconds parameter is optional and controls the extension duration. OpenAI limits the total duration (original + extensions) to 120 seconds for Sora models.

Downloading Content

Download the full video, a thumbnail, or a spritesheet:

import os, openai

client = openai.OpenAI(
    api_key=os.getenv("POE_API_KEY"),
    base_url="https://api.poe.com/v1",
)

# Download the full video (default)
video_content = client.videos.download_content(video_id=video.id)
with open("video.mp4", "wb") as f:
    f.write(video_content.content)

# Download the thumbnail
thumbnail = client.videos.download_content(video_id=video.id, variant="thumbnail")
with open("thumbnail.webp", "wb") as f:
    f.write(thumbnail.content)

# Download the spritesheet
spritesheet = client.videos.download_content(video_id=video.id, variant="spritesheet")
with open("spritesheet.jpg", "wb") as f:
    f.write(spritesheet.content)
# Download the full video (default)
curl "https://api.poe.com/v1/videos/VIDEO_ID/content" \
    -H "Authorization: Bearer $POE_API_KEY" \
    --output video.mp4

# Download the thumbnail
curl "https://api.poe.com/v1/videos/VIDEO_ID/content?variant=thumbnail" \
    -H "Authorization: Bearer $POE_API_KEY" \
    --output thumbnail.webp

# Download the spritesheet
curl "https://api.poe.com/v1/videos/VIDEO_ID/content?variant=spritesheet" \
    -H "Authorization: Bearer $POE_API_KEY" \
    --output spritesheet.jpg

Content variants:

VariantContent-TypeDescription
(default)video/mp4Full video file
thumbnailimage/webpPreview thumbnail
spritesheetimage/jpegSpritesheet of frames

Detailed API Reference

Endpoints

MethodPathDescription
POST/v1/videosCreate a new video
GET/v1/videos/{video_id}Retrieve video status
GET/v1/videos/{video_id}/contentDownload video content
POST/v1/videos/{video_id}/remixRemix an existing video
POST/v1/videos/extensionsExtend a completed video

Create Request Fields

FieldRequiredDescription
modelYesPoe bot name (e.g. Sora-2, Veo-2)
promptYesText description of the video to generate
secondsNoDuration in seconds (default varies by model)
sizeNoResolution as WIDTHxHEIGHT (e.g. 1280x720)
input_referenceNoReference image file (multipart form upload)
input_imageNoBase64-encoded reference image (JSON body)

Remix Request Fields

FieldRequiredDescription
promptYesNew prompt describing the desired style

The model is inherited from the source video. No model parameter is needed.

Extension Request Fields

FieldRequiredDescription
videoYesObject with id of the source video (e.g. {"id": "video_abc123"})
promptYesText description of the continuation
secondsNoDuration of the extension in seconds

The model is inherited from the source video. No model parameter is needed.

Video Response Fields

FieldDescription
idUnique video identifier
objectAlways "video"
statusqueued, in_progress, completed, failed
created_atUnix timestamp of creation
completed_atUnix timestamp of completion (null if not yet complete)
expires_atUnix timestamp when the video content expires
modelModel used for generation
secondsDuration of the video in seconds
sizeResolution as WIDTHxHEIGHT
progressGeneration progress (0-100)
remixed_from_video_idID of the source video (for remixes)
errorError details (if status is failed)
usageToken/point usage information

Supported Models

Poe Bot NameProviderMax DurationFeatures
Sora-2OpenAI20 secondsCreate, status, download, remix, extend
Sora-2-ProOpenAI20 secondsCreate, status, download, remix, extend (1080p)
Veo-2Google Vertex AI8 secondsCreate, status, download
Veo-3Google Vertex AI8 secondsCreate, status, download
Veo-3-FastGoogle Vertex AI8 secondsCreate, status, download
Veo-3.1Google Vertex AI8 secondsCreate, status, download
Veo-3.1-FastGoogle Vertex AI8 secondsCreate, status, download

Note: Default duration when seconds is omitted varies by provider: 4 seconds for OpenAI models, 8 seconds for Vertex AI models.

Known Issues & Limitations

  • Asynchronous only - Video generation does not support streaming. You must poll for completion.
  • Remix and extension: Sora models only - Veo models (Vertex AI) do not support remix or extend operations.
  • Extension requires completed source video - The source video must have status: "completed" before it can be extended.
  • Private bots not supported - Only public bots can be accessed through the API.
  • Characters and video editing not available - The characters and storyboard editing features from OpenAI's platform are not available on Poe.
  • Default resolution is 720x1280 (portrait) - Specify size explicitly if you need a different aspect ratio.

Error Handling

Error responses follow the same format as the OpenAI Compatible API:

{
  "error": {
    "code": 401,
    "type": "authentication_error",
    "message": "Invalid API key",
    "metadata": {}
  }
}
HTTP CodeTypeWhen It Happens
400invalid_request_errorMalformed JSON, missing required fields
401authentication_errorBad or expired API key
402insufficient_creditsPoint balance is zero
404not_foundVideo ID does not exist
429rate_limit_errorRate limit exceeded
500provider_errorProvider-side issues

Retry tips:

  • Respect the Retry-After header on 429 responses
  • Use exponential backoff starting at 250ms with jitter

Pricing & Availability

All Poe subscribers can use their existing subscription points with the API at no additional cost.

This means you can seamlessly transition between the web interface and API without worrying about separate billing structures or additional fees. Your regular monthly point allocation works exactly the same way whether you're chatting directly on Poe or accessing bots programmatically through the API.

If your Poe subscription is not enough, you can now purchase add-on points to get as much access as your application requires. Our intent in pricing these points is to charge the same amount for model access that underlying model providers charge. Any add-on points you purchase can be used with any model or bot on Poe and work across both the API and Poe chat on web, iOS, Android, Mac, and Windows.

Support

Feel free to reach out to support if you come across some unexpected behavior when using our API or have suggestions for future improvements.