> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.videogen.io/handling-async-tasks/polling/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.videogen.io/_mcp/server. # Polling > Poll GET endpoints for async status, or use SDK poll helpers for tool executions, workflow runs, and project exports. The VideoGen API exposes poll endpoints for each async surface. Both SDKs ship helpers that loop until a terminal status is reached. ## Workflow runs After `POST /v1/workflows/*`, poll `GET /v1/workflows/runs/{workflowRunId}` until `status` is `succeeded`, `failed`, or `cancelled`, or use `pollWorkflowRun` / `poll_workflow_run`. The poll response includes `projectId` (use for export/remix) and `projectUrl` (optional app editor link; see [Workflows](/workflows#about-projectid-and-projecturl)). **TypeScript:** ```typescript import { VideoGen, pollWorkflowRun } from "@videogen/sdk"; const client = new VideoGen({ apiKey: "sk_videogen_live_..." }); const { workflowRunId } = await client.workflows.scriptToVideo({ 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.", visualStyle: { type: "AI_IMAGE", aiStyle: "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", autoExport: true, remixActions: [ { type: "ENABLE_CAPTIONS" }, { type: "SET_BACKGROUND_MUSIC", fileId: "vg_file_...", volume: 0.25 }, ], }); const run = await pollWorkflowRun({ client, workflowRunId }); console.log(run.downloadUrl); ``` **Python:** ```python from videogen import VideoGen, poll_workflow_run client = VideoGen(api_key="sk_videogen_live_...") response = client.workflows.script_to_video( 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": "SET_BACKGROUND_MUSIC", "file_id": "vg_file_...", "volume": 0.25}, ], ) run = poll_workflow_run(client, response["workflowRunId"]) print(run.get("download_url") or run.get("downloadUrl")) ``` ## Tool executions Poll `GET /v1/tools/executions/{toolExecutionId}` until the status is `succeeded`, `failed`, or `cancelled`, or use `pollExecutedTool` / `poll_executed_tool`: **TypeScript:** ```typescript import { pollExecutedTool } from "@videogen/sdk"; const { toolExecutionId } = await client.tools.generateImage({ prompt: "A mountain at sunrise", }); const response = await pollExecutedTool({ client, toolExecutionId }); if (response.status === "succeeded") { console.log("File id:", response.results[0].fileId); } ``` **Python:** ```python from videogen import poll_executed_tool response = client.tools.generate_image(prompt="A mountain at sunrise") execution = poll_executed_tool(client, response["toolExecutionId"]) if execution["status"] == "succeeded": print("File id:", execution["results"][0]["fileId"]) ``` **cURL:** ```bash # Repeat until status is "succeeded", "failed", or "cancelled" curl https://api.videogen.io/v1/tools/executions/vg_tool_... \ -H "Authorization: Bearer sk_videogen_live_..." ``` The helper polls every 1.5 seconds (configurable via `pollIntervalMs` / `poll_interval_ms`) and returns once a terminal status is reached. Under the hood it's a simple loop: **TypeScript:** ```typescript async function pollExecutedTool( client: Pick, toolExecutionId: string, options?: { pollIntervalMs?: number; signal?: AbortSignal }, ): Promise { const pollIntervalMs = options?.pollIntervalMs ?? 1500; while (true) { options?.signal?.throwIfAborted(); const executed = await client.tools.getToolExecutionInfo({ toolExecutionId }); if (["succeeded", "failed", "cancelled"].includes(executed.status)) { return executed; } await new Promise((r) => setTimeout(r, pollIntervalMs)); } } ``` **Python:** ```python def poll_executed_tool( client: VideoGen, tool_execution_id: str, *, poll_interval_ms: int = 1500, cancel_event: Optional[Event] = None, ) -> ExecutedTool: while True: poll_raise_if_cancelled(cancel_event) executed = client.tools.get_tool_execution_info( tool_execution_id=tool_execution_id, ) if executed["status"] in ("succeeded", "failed", "cancelled"): return executed poll_sleep(poll_interval_ms, cancel_event) ``` When to use polling: good for scripts, CLI tools, or any situation where you can block and wait. For production systems, consider using [webhooks](/handling-async-tasks/webhooks) instead. ## Public preview After `POST /v1/files/{fileId}/enable-public-preview`, poll `GET /v1/files/{fileId}` until `staticPublicPreviewSource.url` is ready (and `publicPlaybackId` for video/audio embeds), or use `pollPublicPreview` / `poll_public_preview`: **TypeScript:** ```typescript import { pollPublicPreview } from "@videogen/sdk"; await client.files.enablePublicPreview({ fileId }); const preview = await pollPublicPreview({ client, fileId }); console.log(preview.publicPreviewUrl); console.log(preview.publicPlaybackId); // video/audio embed id, when ready ``` **Python:** ```python from videogen import poll_public_preview client.files.enable_public_preview(file_id=file_id) preview = poll_public_preview(client, file_id) print(preview["public_preview_url"]) print(preview["public_playback_id"]) ``` `pollPublicPreview` throws if `isPublicPreviewEnabled` is false. Call `enablePublicPreview` first. Use `waitForEmbedPlaybackId: false` (or `wait_for_embed_playback_id=False`) when you only need the permanent direct URL (e.g. images). ## Project exports After `POST /v1/projects/{projectId}/export`, poll `GET /v1/projects/{projectId}/exports/{exportId}` until `status` is `succeeded`, `failed`, or `cancelled`, or use `pollProjectExport` / `poll_project_export`. Subscribe to `project_export.succeeded`, `project_export.failed`, and `project_export.cancelled` for push notifications. Each response includes `progressPercentage` (0-100) for the current attempt, so you can render a live progress bar while the export runs. It is always `100` once `status` is `succeeded`. > HTTP API with TypeScript and Python SDKs for generating image, video, and audio assets with VideoGen.