> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.videogen.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.videogen.io/_mcp/server.

# Python

> Install and configure the videogen Python package. Covers sync and async clients, video workflows, tool execution polling, file uploads/downloads, and webhook verification.

## Install

```bash
pip install videogen
```

## Create a client

```python
from videogen import VideoGen

vg = VideoGen(api_key="sk_videogen_live_...")
```

The client reads from the `VIDEOGEN_API_KEY` environment variable when no `api_key` is provided.

### Async client

```python
from videogen import AsyncVideoGen

vg = AsyncVideoGen(api_key="sk_videogen_live_...")
```

## Generate a video from a script

Workflows turn a script into a finished video asynchronously. Prefer `script_to_video_and_wait` when you can block:

```python
from videogen import VideoGen

vg = VideoGen(api_key="sk_videogen_live_...")

run = vg.workflows.script_to_video_and_wait(
    script=(
        "Staying hydrated keeps your body and mind running at their best. "
        "Drinking enough water boosts your energy, focus, and mood. "
        "Keep a water bottle nearby and sip throughout the day."
    ),
    visual_style={
        "type": "AI_IMAGE",
        "ai_style": "Loose watercolor illustration, visible brushstrokes, soft color bleeds, paper texture, muted palette. A clear uncluttered subject centered in the frame, occupying only the middle half of the image, with generous empty margins on all four sides, no background clutter.",
    },
    quality="HIGH",
    auto_export=True,
    remix_actions=[
        {"type": "ENABLE_CAPTIONS"},
        {
            "type": "CONVERT_IMAGES_TO_VIDEOS",
            "motion_prompt": "slow cinematic push-in",
            "mute_output_videos": True,
            "quality": "HIGH",
        },
    ],
)

print(run.get("download_url") or run.get("downloadUrl"))
```

Use `project_id` for export, remix, and other API calls. `project_url` (also on the response) is optional: a link to open the project in the VideoGen editor for manual review (team members and project collaborators only).

Request kwargs use snake\_case (and nested dict keys); the client serializes body/query keys to camelCase for the API. Responses are plain dicts with snake\_case keys.

For start-then-poll yourself, call `script_to_video` then `poll_workflow_run(vg, workflow_run_id)`. For the async client, use `script_to_video_and_wait` on `AsyncVideoGen` (or `async_poll_workflow_run`):

```python
from videogen import AsyncVideoGen

vg = AsyncVideoGen(api_key="sk_videogen_live_...")

run = await vg.workflows.script_to_video_and_wait(
    script="Staying hydrated keeps your body and mind running at their best.",
    visual_style={
        "type": "AI_IMAGE",
        "ai_style": "Loose watercolor illustration, visible brushstrokes, soft color bleeds, paper texture, muted palette. A clear uncluttered subject centered in the frame, occupying only the middle half of the image, with generous empty margins on all four sides, no background clutter.",
    },
    quality="HIGH",
    auto_export=True,
    remix_actions=[
        {"type": "ENABLE_CAPTIONS"},
        {
            "type": "CONVERT_IMAGES_TO_VIDEOS",
            "motion_prompt": "slow cinematic push-in",
            "mute_output_videos": True,
            "quality": "HIGH",
        },
    ],
)
print(run.get("download_url") or run.get("downloadUrl"))
```

### Options

| Option             | Type              | Default   | Description                                       |
| ------------------ | ----------------- | --------- | ------------------------------------------------- |
| `poll_interval_ms` | `int`             | `1500`    | Milliseconds between polls.                       |
| `timeout_ms`       | `int`             | `3600000` | Maximum wait time before raising.                 |
| `cancel_event`     | `threading.Event` | (none)    | Cancel sync polling early (`PollCancelledError`). |

For the async client, pass `asyncio.Event` as `cancel_event` to `*_and_wait` methods and async poll helpers (`async_poll_workflow_run`, `async_poll_executed_tool`, `async_poll_project_export`, `async_poll_public_preview`).

## Run a standalone tool

All tool endpoints are asynchronous. Prefer `generate_image_and_wait` (and the other tool `*_and_wait` methods). Use `create_public_preview` when you need a shareable preview URL:

```python
from videogen import VideoGen, create_public_preview

vg = VideoGen(api_key="sk_videogen_live_...")

execution = vg.tools.generate_image_and_wait(
    prompt="A sunset over a calm ocean, cinematic lighting",
)

print(execution["status"])  # "succeeded"
file_id = execution["results"][0]["file_id"]
preview = create_public_preview(vg, file_id)
```

## Upload a file

```python
from videogen import VideoGen, upload_file

vg = VideoGen(api_key="sk_videogen_live_...")

with open("input.mp4", "rb") as f:
    file = upload_file(vg, f, display_name="input.mp4", type="VIDEO")

print(file["file_id"])  # "vg_file_..."
```

## Download a file

```python
from videogen import VideoGen, download_file

vg = VideoGen(api_key="sk_videogen_live_...")

download_file(vg, "vg_file_...", output_path="output.mp4")
```

## Verify a webhook

```python
from videogen import verify_webhook_signature

payload = verify_webhook_signature(
    raw_body=raw_body,
    headers=headers,
    secret=signing_secret,
)

if payload["event"] == "tool_execution.succeeded":
    print(payload["results"])
```

## Links

* [PyPI: videogen](https://pypi.org/project/videogen/)
* [GitHub: videogen-python-sdk](https://github.com/video-gen/videogen-python-sdk)
* [REST API Reference](/rest-api-reference)