> 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.

# Handling async tasks

> How VideoGen async work: tool executions, workflow runs, and project exports return ids immediately, then you poll or use webhooks for the result.

End-to-end video workflows and standalone media generation (images, video, audio) take anywhere from a few seconds to several minutes. Rather than holding a connection open for that entire time, the VideoGen API returns a response instantly with a run or execution id. You then choose how to receive the result: [poll for it](/handling-async-tasks/polling), or let us [push it to you via a webhook](/handling-async-tasks/webhooks).

## Workflow runs

```
POST /v1/workflows/script-to-video  →  { "workflowRunId": "vg_work_...", "projectId": "vg_proj_...", "projectUrl": "..." }
```

Every `POST /v1/workflows/*` endpoint returns `202 Accepted` with `{ workflowRunId, projectId, projectUrl }`. Store `projectId` for export, remix, and other API calls. `projectUrl` is only for opening the project in the VideoGen editor (optional in API-only flows). See [Workflows: About projectId and projectUrl](/workflows#about-projectid-and-projecturl). The run progresses through these statuses:

| Status      | Meaning                  |
| ----------- | ------------------------ |
| `pending`   | Queued, waiting to start |
| `running`   | Generation in progress   |
| `succeeded` | Done, the video is ready |
| `failed`    | Something went wrong     |
| `cancelled` | Cancelled by you         |

`succeeded`, `failed`, and `cancelled` are terminal statuses. The run won't change after reaching one of these. Poll `GET /v1/workflows/runs/{workflowRunId}` until terminal, or subscribe to `workflow_run.*` webhooks.

See [Workflows](/workflows) for available pipelines and SDK helpers (`pollWorkflowRun` / `poll_workflow_run`).

Cancel an in-progress workflow run:

```bash
POST /v1/workflows/runs/{workflowRunId}/cancel
```

## Tool executions

```
POST /v1/tools/generate-image  →  { "toolExecutionId": "vg_tool_..." }
```

Standalone media tools work the same way. Every `POST /v1/tools/...` endpoint returns `202 Accepted` with a `toolExecutionId` and the same set of statuses (`pending`, `running`, `succeeded`, `failed`, `cancelled`).

Cancel an in-progress tool execution:

```bash
POST /v1/tools/executions/{toolExecutionId}/cancel
```

## Project exports

```
POST /v1/projects/{projectId}/export  →  { "exportId": "vg_expo_..." }
```

`POST /v1/projects/{projectId}/export` returns `202 Accepted` with `{ exportId }` and the same statuses as workflow runs (`pending`, `running`, `succeeded`, `failed`, `cancelled`). Poll `GET /v1/projects/{projectId}/exports/{exportId}` until terminal, or subscribe to `project_export.*` webhooks. See [Export your video](/export-your-video). SDK helpers: `pollProjectExport` / `poll_project_export`.

## Getting the result

There are two ways to know when async work finishes:

| Method                                     | Best for                                                                                          |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| [Polling](/handling-async-tasks/polling)   | Scripts, CLI tools, or any situation where you can block and wait.                                |
| [Webhooks](/handling-async-tasks/webhooks) | Production backends, serverless functions, and anywhere you don't want to hold a connection open. |