# Detect AI-Generated Videos

> Use the AI Video Detection API to check if a video is AI-generated via an async submit-and-webhook flow.

The Copyleaks AI Video Detection API, part of the Copyleaks [AI Detector](https://copyleaks.com/ai-detector), analyzes whether a video was generated or partially generated by AI. The API is **asynchronous**, you submit a video URL, and Copyleaks notifies your server via webhook when the results are ready.

This guide walks through submitting a [video for AI detection](https://copyleaks.com/ai-video-detector) and interpreting the webhook response.

<Tip>
**Just want to try it?** Open the [Video Detection Playground](https://api.copyleaks.com/dashboard/playground/video-detection) to submit a sample video and inspect the webhook response in your browser, no code required.
</Tip>

## Get started

<Steps>
  <Step>
    ### Before you begin
    <BeforeYouBegin />
  </Step>

  <Step>
    ### Installation
    <InstallSDKs />
  </Step>

  <Step>
    ### Login
    <HowToLogin />
  </Step>

  <Step>
    ### Submit a video for analysis
    Use the [AI Video Detector endpoint](/reference/actions/ai-video-detector/submit) to submit a video URL for analysis. Provide a unique `scanId` for each submission and a webhook URL to receive the results.

    <Tip title="Async flow">
      This API is asynchronous. The submission returns `201 Created` immediately, and the detection results are sent to your webhook URL once processing completes.
    </Tip>

    #### Providing a video URL

    The API requires a **publicly accessible URL** pointing to your video file - Copyleaks will fetch it directly. The video must be reachable at the time of processing, so avoid URLs that expire before the scan completes.

    A common approach is to upload the video to cloud storage and generate a pre-signed URL:

    - **Amazon S3** - Upload the file to an S3 bucket and generate a [pre-signed URL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html) with a sufficient expiry window (e.g. 1 hour). The bucket does not need to be public.
    - **Google Cloud Storage** - Upload to a GCS bucket and create a [signed URL](https://cloud.google.com/storage/docs/access-control/signed-urls) using the GCS console or SDK.
    - **Azure Blob Storage** - Upload to a container and generate a [SAS URL](https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview) with read access.
    - **Any CDN or file host** - Any URL that returns the raw video file with a `Content-Type` video header works.

    <Tip title="Private or authenticated video URLs">
      If your video is hosted behind authentication (e.g. a signed URL that also requires a token header, or an internal storage service), use the top-level `headers` field in the request body to pass the necessary HTTP headers. Copyleaks will include these headers when fetching the video.

      For example, to pass a bearer token:

      ```json
      "headers": [["Authorization", "Bearer YOUR_TOKEN"]]
      ```

      Each entry in the array is a `["Header-Name", "Header-Value"]` pair. You can include multiple headers by adding more pairs to the array.
    </Tip>

    #### Setting up your webhook

    The `webhooks.url` field is where Copyleaks will `POST` the detection results when processing is done. This must be a publicly reachable HTTPS endpoint on your server.

    A few tips for getting started:

    - **During development** - Use a tool like [ngrok](https://ngrok.com/) or [webhook.site](https://webhook.site/) to expose a local server or inspect incoming payloads without writing any backend code.
    - **In production** - Implement a route in your API (e.g. `POST /webhook/video-results`) that receives the payload, validates it, and stores or acts on the results.
    - **Security** - Use the optional `webhooks.headers` field to pass a secret token with the webhook request, which your server can verify to ensure the request is coming from Copyleaks.

    #### Video requirements

    **Returned as `400 Bad Request` at submit (synchronous):**

    - Missing or invalid `scanId`, `filename`, `url`, `model`, or `webhooks`
    - Unsupported file extension (supported: `.mp4`, `.avi`, `.mov`, `.mkv`, `.webm`, `.flv`, `.wmv`, `.mpg`, `.m4v`, `.3gp`, `.mxf`)
    - Filename longer than 255 characters
    - Invalid `verb` value

    **Delivered to your webhook as an error result (asynchronous):**

    - Duration outside 2 seconds-1 hour → `video_too_short` (67) / `video_too_long` (68)
    - File larger than 512 MiB → `file_too_large` (6)
    - Resolution below 360×360 → `video_resolution_too_low` (65)
    - Frame rate below 16 FPS → `fps_too_low` (66)
    - Undecodable codec → `unsupported_video_codec` (71)
    - Corrupt or truncated file → `video_truncated` (70)
    - Generic decode failure → `video_load_failed` (72)

    <Tip>
      For testing, set `"sandbox": true`. Sandbox mode is free and returns mock results.
    </Tip>

    <CodeGroup>
        ```http title="HTTP" icon="globe"
        POST https://api.copyleaks.com/v1/ai-video-detector/my-video-scan-1/submit

        Headers
        Authorization: Bearer <YOUR_AUTH_TOKEN>
        Content-Type: application/json

        Body
        {
          "url": "https://example.com/my-video.mp4",
          "filename": "my-video.mp4",
          "model": "ai-video-1-pro",
          "sandbox": true,
          "webhooks": {
            "url": "https://your-server.com/webhook/receive-results"
          }
        }
        ```
        ```bash title="cURL" icon="terminal"
        curl -X POST "https://api.copyleaks.com/v1/ai-video-detector/my-video-scan-1/submit" \
             -H "Authorization: Bearer <YOUR_AUTH_TOKEN>" \
             -H "Content-Type: application/json" \
             -d '{
               "url": "https://example.com/my-video.mp4",
               "filename": "my-video.mp4",
               "model": "ai-video-1-pro",
               "sandbox": true,
               "webhooks": {
                 "url": "https://your-server.com/webhook/receive-results"
               }
             }'
        ```
        ```python title="Python" icon="python"
        import requests

        url = 'https://api.copyleaks.com/v1/ai-video-detector/my-video-scan-1/submit'
        headers = {
            'Authorization': 'Bearer YOUR_LOGIN_TOKEN',
            'Content-Type': 'application/json'
        }

        payload = {
            'url': 'https://example.com/my-video.mp4',
            'filename': 'my-video.mp4',
            'model': 'ai-video-1-pro',
            'sandbox': True,
            'webhooks': {
                'url': 'https://your-server.com/webhook/receive-results'
            }
        }

        response = requests.post(url, json=payload, headers=headers)
        print(f"Submission status: {response.status_code}")  # Expect 201 Created
        ```
        ```javascript title="JavaScript" icon="square-js"
        const response = await fetch(
          'https://api.copyleaks.com/v1/ai-video-detector/my-video-scan-1/submit',
          {
            method: 'POST',
            headers: {
              'Authorization': 'Bearer YOUR_LOGIN_TOKEN',
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              url: 'https://example.com/my-video.mp4',
              filename: 'my-video.mp4',
              model: 'ai-video-1-pro',
              sandbox: true,
              webhooks: {
                url: 'https://your-server.com/webhook/receive-results'
              }
            })
          }
        );

        console.log('Submission status:', response.status); // Expect 201 Created
        ```
    </CodeGroup>
  </Step>

  <Step>
    ### Receive the webhook result
    Once Copyleaks finishes analyzing the video, it sends a POST request to your webhook URL with the detection results.

    #### Example webhook payload

    ```json
    {
      "model": "ai-video-1-pro",
      "audioResult": {
        "starts": [13000, 45000, 47000],
        "lengths": [14000, 1000, 8700],
        "exclude": {
          "starts": [0, 3250, 5400, 7600, 10500],
          "lengths": [2950, 1500, 1200, 650, 1050]
        }
      },
      "visualResult": {
        "starts": [11566, 29433],
        "lengths": [6134, 26267],
        "exclude": {
          "starts": [],
          "lengths": []
        }
      },
      "summary": {
        "audioAIRatio": 0.4902,
        "visualAIRatio": 0.5817,
        "overallAIRatio": 0.7487
      },
      "videoInfo": {
        "metadata": {
          "issuedTime": "2026-03-17T13:14:57+00:00",
          "issuedBy": "OpenAI",
          "appOrDeviceUsed": "Sora",
          "contentSummary": "Created using generative AI"
        },
        "duration": 55.7
      },
      "scannedVideo": {
        "scanId": "my-video-scan-1",
        "actualCredits": 1,
        "expectedCredits": 1,
        "creationTime": "2026-05-05T12:37:50Z"
      }
    }
    ```

    #### Understanding the results

    The webhook response contains three key sections:

    **`audioResult` and `visualResult`** - Time-based detections for the audio and visual tracks, encoded as arrays of start positions (`starts`) and durations (`lengths`) in milliseconds.

    The `exclude` object within each result identifies segments that were **not scored**. These ranges are excluded because the content could not be meaningfully analyzed, and they are not counted in the AI ratio calculations.

    **`summary`** - Overall AI ratios. Segments listed in `exclude` are not counted in any of these calculations:

    - `audioAIRatio` - Ratio of AI-detected audio duration to total audible duration. Excluded audio ranges are not counted (0.0-1.0).
    - `visualAIRatio` - Ratio of AI-detected visual duration to total visible duration. Excluded visual ranges are not counted (0.0-1.0).
    - `overallAIRatio` - Combined AI ratio across both audio and visual tracks, relative to the total video duration (0.0-1.0).

    **`videoInfo`** - Video duration and optional C2PA/embedded metadata identifying the generating tool.

    For a complete breakdown of all response fields, see the [AI Video Detection Response](/reference/data-types/ai-detector/ai-video-detection-response) documentation.
  </Step>

  <Step>
    ### You're done
    You've successfully submitted a video for AI detection and received the webhook results. You can now use `summary.overallAIRatio` and the time-based `audioResult` / `visualResult` data in your application.
  </Step>
</Steps>

## Next steps

<CardGroup cols={3}>
  <Card title="API Reference" icon="code" href="/reference/actions/ai-video-detector/submit">
    The complete reference for the AI Video Detection endpoint.
  </Card>
  <Card title="AI Video Detection Response" icon="brackets-curly" href="/reference/data-types/ai-detector/ai-video-detection-response">
    The complete webhook response structure.
  </Card>
  <Card title="AI Image Detection Guide" icon="image" href="/guides/ai-detector/ai-image-detection">
    Detect AI-generated images using the synchronous image detection API.
  </Card>
</CardGroup>
