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

# Export your video

> Step three of the VideoGen flow: export a project with POST /v1/projects/{projectId}/export, then poll or wait for project_export.* webhooks before downloading the MP4.

Once a workflow has built your project (and any remix actions have finished), export it to an MP4. The export runs asynchronously: start it, poll until it finishes, then download from the returned URL. You can also subscribe to `project_export.succeeded`, `project_export.failed`, and `project_export.cancelled` instead of polling.

## Export and download

Start the export, then poll until `status` is `succeeded`. The SDK helpers `pollProjectExport` (TS) and `poll_project_export` (Python) loop for you and return the `downloadUrl`.

#### TypeScript

```typescript
import { VideoGen, pollProjectExport } from "@videogen/sdk";

const client = new VideoGen({ apiKey: "sk_videogen_live_..." });

const { exportId } = await client.projects.exportProject({ projectId });

const projectExport = await pollProjectExport({ client, projectId, exportId });
console.log(projectExport.status, projectExport.downloadUrl);
```

#### Python

```python
from videogen import VideoGen, poll_project_export

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

response = client.projects.export_project(project_id=project_id)

project_export = poll_project_export(client, project_id, response["exportId"])
print(project_export["status"], project_export["downloadUrl"])
```

#### cURL

```bash
# Start the export
curl -X POST https://api.videogen.io/v1/projects/PROJECT_ID/export \
  -H "Authorization: Bearer sk_videogen_live_..."

# Poll until status is "succeeded" (replace the export id)
curl https://api.videogen.io/v1/projects/PROJECT_ID/exports/EXPORT_ID \
  -H "Authorization: Bearer sk_videogen_live_..."
```

Each poll response includes `progressPercentage` (0-100) for the current attempt, so you can render a live progress bar. The `downloadUrl` is present once `status` is `succeeded`.

## Wait with a webhook

Instead of polling, subscribe to `project_export.succeeded`, `project_export.failed`, and `project_export.cancelled`. These fire only for exports started via the API. The payload includes `exportId`, `projectId`, and `exportFileId` (set on success). Fetch signed download URLs with `GET /v1/projects/{projectId}/exports/{exportId}`, or hydrate `exportFileId`. See [Webhooks](/handling-async-tasks/webhooks).

## Watermark and end screen

Exporting requires a paid plan in the app, but the API lets you export for free. Exports below Pro carry two pieces of VideoGen branding: a watermark overlaid on the video (`watermarkMode`) and a short "Made with VideoGen" end screen appended to it (`endScreenMode`). With a Pro plan you can remove either or both. Below Pro, a request to remove them returns an error.

To export with no VideoGen branding, use a Pro plan and set both to `NONE`:

```typescript
const { exportId } = await client.projects.exportProject({
  projectId,
  watermarkMode: "NONE",
  endScreenMode: "NONE",
});
```

`watermarkMode` accepts:

| Value            | Behavior                                                         |
| ---------------- | ---------------------------------------------------------------- |
| `AUTO` (default) | Applies the VideoGen watermark unless you have a Pro plan.       |
| `VIDEO_GEN`      | Always applies the VideoGen watermark.                           |
| `NONE`           | Removes the watermark. Requires Pro; returns an error otherwise. |

`endScreenMode` accepts the same values and behaves the same way, for the "Made with VideoGen" end screen:

| Value            | Behavior                                                                |
| ---------------- | ----------------------------------------------------------------------- |
| `AUTO` (default) | Appends the "Made with VideoGen" end screen unless you have a Pro plan. |
| `VIDEO_GEN`      | Always appends the end screen.                                          |
| `NONE`           | Removes the end screen. Requires Pro; returns an error otherwise.       |

Both default to `AUTO`, so leaving them unset keeps your exports working on every plan: branding is applied below Pro and dropped on Pro.

## Signed URLs and expiry

`downloadUrl` and `thumbnailUrl` are private signed URLs. Each is valid for 7 days from when it was signed (`downloadUrlExpiresAt` and `thumbnailUrlExpiresAt` give the exact expiry, in seconds since epoch). Getting the export re-signs a URL automatically when it is within an hour of expiring, so a fresh call to `GET /v1/projects/{projectId}/exports/{exportId}` always returns a URL that is valid long enough to use. Once the export has finished, you can rely on this endpoint to always hand back a working URL: don't cache the URL string long-term, just fetch the export again when you need it.

A succeeded export also returns the full hydrated export `file` object (same shape as `GET /v1/files/{fileId}`), so you have the file's metadata and every rendition's signed URLs in one call.

> **Note**
>
> **Every endpoint that returns hydrated files auto-rehydrates.** Any response that carries signed file URLs — `GET /v1/projects/{projectId}/exports/{exportId}`, `GET /v1/tools/executions/{toolExecutionId}`, and the like — re-signs URLs that are within an hour of expiring before returning them, so you never receive an already-expired URL from these endpoints. The only exceptions are the file endpoints themselves — `GET /v1/files/{fileId}` and `POST /v1/files/{fileId}/hydrate` — which are the explicit, on-demand hydration paths you call directly when you're holding just a file id.

The response also includes `exportFileId`, the file id of the exported MP4. Pass it to `POST /v1/files/{fileId}/hydrate` to fetch fresh signed URLs straight from the file at any time (useful if you kept only the file id and the 24-hour URLs have since expired).

## Managing projects

The Projects API also lets you list and inspect projects:

| Method | Path                                          | Purpose                                                                                                                                                                               |
| ------ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/v1/projects`                                | List projects (`selfOnly=true` scopes to the key owner; default is team-wide). API-created only by default; pass `includeUiProjects=true` to also include dashboard-created projects. |
| `GET`  | `/v1/projects/{projectId}`                    | Project metadata (includes optional `projectUrl` for the app editor).                                                                                                                 |
| `POST` | `/v1/projects/{projectId}/export`             | Start an export; returns `{ exportId }`.                                                                                                                                              |
| `GET`  | `/v1/projects/{projectId}/exports`            | List a project's export ids, newest first.                                                                                                                                            |
| `GET`  | `/v1/projects/{projectId}/exports/{exportId}` | Poll export status; `downloadUrl` when `status` is `succeeded`.                                                                                                                       |

## Next steps

* [Embedding videos](/embedding-videos): Make a file publicly streamable and embed it with the VideoGen player.
* [Handling async tasks](/handling-async-tasks): Poll or use webhooks for export completion.
* [REST API reference](/rest-api-reference): Full endpoint documentation.