> ## Documentation Index
> Fetch the complete documentation index at: https://apidoc.cometapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Use polling and webhooks for video generation

> Track CometAPI video generation with polling and webhooks by storing task IDs, checking task status, and handling callback delivery failures.

Use polling as the baseline for video generation because every async job returns a task ID that you can query. Add webhooks only when the selected video endpoint supports callback URLs, and keep polling as the source of truth for missed or provider-specific callback delivery.

## Create a video task

The following request creates a minimal video task and stores the returned ID. Add duration, resolution, or callback fields only when the selected model page documents those fields.

```bash theme={null}
curl https://api.cometapi.com/v1/videos \
  -H "Authorization: Bearer $COMETAPI_KEY" \
  -F "model=doubao-seedance-2-0" \
  -F "prompt=A cinematic shot of a paper airplane crossing a desk"
```

The response includes a task ID and status:

```json theme={null}
{
  "id": "task_example",
  "task_id": "task_example",
  "object": "video",
  "model": "doubao-seedance-2-0",
  "status": "queued",
  "progress": 0,
  "created_at": 1779872000
}
```

## Poll status

The following request checks the video task status:

```bash theme={null}
curl https://api.cometapi.com/v1/videos/task_example \
  -H "Authorization: Bearer $COMETAPI_KEY"
```

The response changes as the task progresses. Completed responses can include `video_url` when the model adapter has a result URL; otherwise use model-specific result fields or the `/v1/videos/{id}/content` content route when that model supports proxied downloads.

```json theme={null}
{
  "id": "task_example",
  "object": "video",
  "model": "doubao-seedance-2-0",
  "status": "completed",
  "progress": 100,
  "completed_at": 1779872300,
  "video_url": "<generated-video-url>"
}
```

## Receive a webhook

CometAPI does not define one universal callback payload for every video model. Treat callbacks as provider-specific pass-through events, store the raw body, and reconcile final state with polling.

The following Express handler accepts a video callback and stores the event:

```javascript theme={null}
import express from "express";

const app = express();
app.use(express.json({ limit: "2mb" }));

app.post("/cometapi/video-webhook", async (request, response) => {
  const event = request.body;

  console.log("Task ID:", event.task_id || event.id);
  console.log("Status:", event.status);

  response.status(200).json({ received: true });
});

app.listen(3000);
```

A callback payload commonly includes task identity and status fields, but exact nesting depends on the selected model or provider:

```json theme={null}
{
  "task_id": "task_example",
  "status": "completed",
  "progress": 100,
  "result": {
    "video_url": "https://example.com/result.mp4"
  }
}
```

## Common errors

| Error                              | Fix                                                                                                                          |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| Lost callback                      | Poll by task ID until your app has stored a terminal state.                                                                  |
| Duplicate callback                 | Make callback handling idempotent by task ID.                                                                                |
| Callback rejected                  | Return a `2xx` response quickly, then process the job in the background.                                                     |
| Provider-specific payload mismatch | Store the raw callback payload and normalize it in your app.                                                                 |
| Missing `video_url`                | Treat `video_url` as optional and use polling plus model-specific result fields or `/v1/videos/{id}/content` when available. |

## Related links

* [Video Models](/api/video)
* [Create video](/api/video/sora-2/create)
* [Retrieve video](/api/video/sora-2/retrieve)
* [Models page](/overview/models)
* [Model directory](https://www.cometapi.com/models/)
* [Pricing](https://www.cometapi.com/pricing/)

<script type="application/ld+json">
  {`
    {
    "@context": "https://schema.org",
    "@graph": [
      {
        "@type": "TechArticle",
        "@id": "https://apidoc.cometapi.com/guides/webhook-and-polling-for-video-generation",
        "headline": "How do I use webhooks and polling for video generation?",
        "description": "Use polling and webhooks for CometAPI video generation by storing task IDs, checking task status, and handling callback delivery failures.",
        "url": "https://apidoc.cometapi.com/guides/webhook-and-polling-for-video-generation",
        "author": {
          "@type": "Organization",
          "name": "CometAPI"
        },
        "publisher": {
          "@type": "Organization",
          "name": "CometAPI",
          "url": "https://www.cometapi.com"
        }
      },
      {
        "@type": "BreadcrumbList",
        "itemListElement": [
          {
            "@type": "ListItem",
            "position": 1,
            "name": "CometAPI Docs",
            "item": "https://apidoc.cometapi.com/"
          },
          {
            "@type": "ListItem",
            "position": 2,
            "name": "Guides",
            "item": "https://apidoc.cometapi.com/guides/use-cometapi-with-openai-sdk"
          },
          {
            "@type": "ListItem",
            "position": 3,
            "name": "How do I use webhooks and polling for video generation?",
            "item": "https://apidoc.cometapi.com/guides/webhook-and-polling-for-video-generation"
          }
        ]
      }
    ]
    }
    `}
</script>
