# Detect AI-Generated Content in Documents

> Step-by-step guide to detecting AI-generated text in PDF, DOCX, and TXT documents with the Copyleaks API - submit, scan, and export results.

The Copyleaks Authenticity API is a powerful way to analyze your content for AI-generated text. It allows you to scan documents like PDF, DOCX, TXT, and other [formats](/reference/actions/miscellaneous/supported-ai-text-detection-file-types) to detect whether content was written by humans or generated by AI.

This guide will walk you through the process of submitting a document, enabling AI content detection, and exporting the results.

## Get started

<Steps>
  <Step>
    ### Before you begin
    Before you start, ensure you have the following:
    - An active Copyleaks account. If you don't have one, **[sign up for free](https://api.copyleaks.com/signup)**.
    - You can find your API key on the **[API Dashboard](https://api.copyleaks.com/dashboard)**.
  </Step>

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

  <Step>
    ### Login
    <GuideLogin />
  </Step>

  <Step>
    ### Submit for scanning
    <SubmissionMethods />
    
    For this guide, we'll demonstrate document submission. Each submission requires a unique `scanId` for proper tracking and identification.
    <Note title="File Submission Requirements">
    - **Filename:** The file extension in the `filename` parameter must match your document type (e.g., `.pdf`, `.docx`, `.txt`). See the
     full [list of supported ai text detection file types](/reference/actions/miscellaneous/supported-ai-text-detection-file-types).
    - **Content Encoding:** The file content must be Base64 encoded and sent in the `base64` property.
    </Note>
    
    <Note>
    **What is Base64 Encoding?**

    Base64 converts binary files into text strings so they can be sent via JSON. All programming languages have built-in Base64 encoding functions, see the code examples below for your language.
    </Note>
    
    <Tip>
    For testing, set `"sandbox": true`. Sandbox mode is free and returns mock results. <br/>
    To enable AI detection, ensure `"aiGeneratedText": {"detect": true}` is set in your properties.
    </Tip>
    
    <CodeGroup>
        ```http title="HTTP" icon="globe"
        PUT https://api.copyleaks.com/v3/scans/submit/file/my-ai-detection-scan

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

        Body
        {
            "base64": "<BASE64_ENCODED_PDF_CONTENT>",
            "filename": "my-file.pdf",
            "properties": {
                "webhooks": {
                  "status": "https://your-server.com/webhook/{STATUS}"
                  },
                "sandbox": true,
                "aiGeneratedText": {
                    "detect": true
                }
            }
        }
        ```
      ```bash title="cURL" icon="terminal"
      # First, encode your PDF file to base64
      base64_content=$(base64 -w 0 my-file.pdf)
      
      curl -X PUT "https://api.copyleaks.com/v3/scans/submit/file/my-ai-detection-scan" \
           -H "Authorization: Bearer <YOUR_AUTH_TOKEN>" \
           -H "Content-Type: application/json" \
           -d "{
                 \"base64\": \"$base64_content\",
                 \"filename\": \"my-file.pdf\",
                 \"properties\": {
                   \"webhooks\": {
                     \"status\": \"https://your-server.com/webhook/{STATUS}\"
                   },
                   \"sandbox\": true,
                   \"aiGeneratedText\": {
                     \"detect\": true
                   },
                   \"scanning\": {
                     \"internet\": false
                   }
                 }
               }"
      ```
      ```python title="Python" icon="python"
      import base64
      import random
      from copyleaks.copyleaks import Copyleaks
      from copyleaks.models.submit.document import FileDocument
      from copyleaks.models.submit.properties.scan_properties import ScanProperties
      from copyleaks.models.submit.properties.submit_webhooks import SubmitWebhooks
      from copyleaks.models.submit.properties.ai_generated_text import AIGeneratedText

      print("Submitting a PDF file for AI detection...")
      
      # Read and encode the PDF file
      with open('my-file.pdf', 'rb') as pdf_file:
          pdf_content = pdf_file.read()
          BASE64_FILE_CONTENT = base64.b64encode(pdf_content).decode('utf8')
      
      FILENAME = "my-file.pdf"  # Important: extension must match file type
      scan_id = random.randint(100, 100000)  # generate a random scan id
      file_submission = FileDocument(BASE64_FILE_CONTENT, FILENAME)
      
      # Configure AI-generated text detection
      ai_generated_text = AIGeneratedText()
      ai_generated_text.detect = True  # Enable AI detection
      
      # Configure webhooks for notifications
      webhooks = SubmitWebhooks()
      webhooks.set_status('https://your.server/webhook/{STATUS}')
      webhooks.set_new_result('https://your.server/webhook/new-results')

      # Pass the webhooks and AI detection settings to ScanProperties
      scan_properties = ScanProperties(status_webhook='https://your.server/webhook/{STATUS}')
      scan_properties.set_webhooks(webhooks)
      scan_properties.set_ai_generated_text(ai_generated_text)
      scan_properties.set_sandbox(True)  # Turn on sandbox mode. Turn off on production.
      file_submission.set_properties(scan_properties)
      
      Copyleaks.submit_file(auth_token, scan_id, file_submission)
      print("PDF sent to scanning")
      print("You will be notified via webhook when the scan completes.")
      ```
      ```javascript title="JavaScript" icon="square-js"
      const { Copyleaks, CopyleaksFileSubmissionModel } = require('plagiarism-checker');
      const fs = require('fs');

      async function submitFileForAiDetection() {
          try {
              // Initialize Copyleaks
              const copyleaks = new Copyleaks();
              
              // Login to get the authentication token.
              // Replace with your email and API key.
              const loginResult = await copyleaks.loginAsync('YOUR_EMAIL@example.com', 'YOUR_API_KEY');

              const scanId = `ai-scan-${Date.now()}`;
              const WEBHOOK_URL = "https://your-server.com/webhook";

              // Read a file and convert it to base64
              const filePath = 'path/to/your/document.pdf';
              const fileContent = fs.readFileSync(filePath);
              const base64Content = fileContent.toString('base64');

              // Create a submission model
              const submission = new CopyleaksFileSubmissionModel(
                  base64Content,
                  'document.pdf',
                  {
                      sandbox: true, // Use sandbox for testing
                      webhooks: {
                          // Copyleaks will notify this URL when the scan is complete.
                          status: `${WEBHOOK_URL}/{STATUS}`
                      },
                      aiGeneratedText: {
                          detect: true // Enable AI detection
                      }
                  }
              );

              // Submit the file for scanning
              await copyleaks.submitFileAsync(loginResult, scanId, submission);
              console.log(`Submission successful. Scan ID: ${scanId}`);

          } catch (error) {
              console.error("An error occurred:", error);
          }
      }

      submitFileForAiDetection();
      ```
      ```java title="Java" icon="java"
      import classes.Copyleaks;
      import models.submissions.CopyleaksFileSubmissionModel;
      import models.submissions.properties.*;
      import java.util.Base64;
      import java.nio.file.Files;
      import java.nio.file.Paths;
      import java.io.IOException;

      String scanId = "my-ai-detection-scan";
      
      // Read and encode the PDF file
      byte[] pdfBytes = Files.readAllBytes(Paths.get("my-file.pdf"));
      String base64Content = Base64.getEncoder().encodeToString(pdfBytes);

      // Configure webhooks
      SubmissionWebhooks webhooks = new SubmissionWebhooks("https://your-server.com/webhook/{STATUS}");
      webhooks.setNewResult("https://your-server.com/webhook/new-results");

      // Create submission properties
      SubmissionProperties properties = new SubmissionProperties(webhooks);
      properties.setSandbox(true);

      // Configure AI-generated text detection
      SubmissionAIGeneratedText aiGeneratedText = new SubmissionAIGeneratedText();
      aiGeneratedText.setDetect(true);
      properties.setAiGeneratedText(aiGeneratedText);

      // Set action to scan for AI content
      properties.setAction(SubmissionActions.Scan);

      // Create and submit the file - Important: extension must match file type
      CopyleaksFileSubmissionModel submission = new CopyleaksFileSubmissionModel(
          base64Content, 
          "my-file.pdf", 
          properties
      );

      Copyleaks.submitFile(authToken, scanId, submission);
      System.out.println("PDF sent to scanning...");
      ```
    </CodeGroup>
  </Step>

  <Step>
    ### Wait for the completion webhook
    The scan times differ depending on document length. Once it's complete, Copyleaks will send a [completed webhook](/reference/data-types/authenticity/webhooks/scan-completed) to the status URL you provided.

    <Note title="Webhook Response Reference">
    For complete details on the webhook response structure, see the [Scan Completed Webhook Reference](/reference/data-types/authenticity/webhooks/scan-completed).
    </Note>
  </Step>

  <Step>
    ### Interpreting AI detection results
    When the scan is complete, check the `notifications.alerts` array in the webhook payload.                                       
    - If the array is empty or does not contain an alert with the code `suspected-ai-text`, you can assume no AI-generated content was detected.                                                                                                                   
    - If such an alert is present, you can inspect its `additionalData` field for a detailed summary of the [AI Detector](https://copyleaks.com/ai-detector) results.    
  </Step>

  <Step>
    ### Export detailed results

    Once the scan is complete, you'll receive a `completed` webhook. To get the full analysis needed to display a report, you need to export two key pieces of data using the [export endpoint](/reference/actions/downloads/export):

    1.  **AI Detection Results**: It provides a detailed breakdown of which parts of the text were identified as potentially AI-generated. You'll receive a result ID for the AI detection in the `completed` webhook, which you'll use for the export. See the [AI Detection Result data type](/reference/data-types/authenticity/results/ai-detection).

    2.  **Crawled Version**: This is the plain text or HTML representation of the original scanned document. See the [Crawled Version data type](/reference/data-types/authenticity/results/crawled-version).

    Your export request must specify a `completionWebhook` to be notified when the exported data is ready for download.

    <CodeGroup>
        ```http title="HTTP" icon="globe"
        POST https://api.copyleaks.com/v3/downloads/my-ai-detection-scan/export/<export_id>

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

        Body
        {
            "completionWebhook":  "https://your.server/export/completed",
            "maxRetries": 3,
            "developerPayload": "custom_data_identifier",
            "crawledVersion": {
                "endpoint": "https://your.server/webhook/export/crawled",
                "verb": "POST",
                "headers": [
                    [
                        "header-key",
                        "header-value"
                    ]
                ]
            },
            "results": [
                {
                    "id": "ai-result-1",
                    "endpoint": "https://your.server/webhook/export/ai-result/ai-result-1",
                    "verb": "POST",
                    "headers": [
                        [
                            "header-key",
                            "header-value"
                        ]
                    ]
                }
            ]
        }
        ```
      ```bash title="cURL" icon="terminal"
      curl -X POST "https://api.copyleaks.com/v3/downloads/my-ai-detection-scan/export/my-export-1" \
          -H "Authorization: Bearer <YOUR_AUTH_TOKEN>" \
          -H "Content-Type: application/json" \
          -d '{
                "completionWebhook": "https://your-server.com/webhook/export/completion",
                "maxRetries": 3,
                "developerPayload": "custom_data_identifier",
                "crawledVersion": {
                    "endpoint": "https://your-server.com/webhook/export/crawled",
                    "verb": "POST",
                    "headers": {
                        "header-key": "header-value",
                        "header-key-2": "header-value-2"
                    }
                },
                "results": [
                    {
                        "id": "<AI_RESULT_ID_FROM_COMPLETED_WEBHOOK>",
                        "endpoint": "https://your-server.com/webhook/export/ai-result/1",
                        "verb": "POST",
                        "headers": {
                            "header-key": "header-value"
                        }
                    }
                ]
              }'
      ```
      ```python title="Python" icon="python"
      from copyleaks.copyleaks import Copyleaks
      from copyleaks.models.export import Export, ExportResult

      export_id = "my-export-1"
      export = Export()
      export.set_completion_webhook('https://your-server.com/webhook/export/completion')

      # Export a specific AI detection result
      result1 = ExportResult()
      result1.set_id('<AI_RESULT_ID_FROM_COMPLETED_WEBHOOK>')
      result1.set_endpoint('https://your-server.com/webhook/export/ai-result/1')  # Only URL
      result1.set_verb('POST')  # HTTP method separately
      export.set_results([result1])

      Copyleaks.export(auth_token, scan_id, export_id, export)
      print("Export initiated.")
      ```
      ```javascript title="JavaScript" icon="square-js"
        const { Copyleaks, CopyleaksExportModel } = require('plagiarism-checker');

        async function exportAiDetectionResults() {
            try {
                // Initialize Copyleaks
                const copyleaks = new Copyleaks();

                // Login to get the authentication token.
                // Replace with your email and API key.
                const loginResult = await copyleaks.loginAsync('YOUR_EMAIL@example.com', 'YOUR_API_KEY');

                const scanId = "YOUR_SCAN_ID"; // The ID of the scan you want to export
                const exportId = `export-${scanId}-${Date.now()}`;
                const WEBHOOK_URL = "https://your-server.com/webhook";
                
                // The AI detection result ID to export, obtained from the completion webhook
                const aiResultId = "AI_RESULT_ID_FROM_WEBHOOK"; 

                const results = [{
                    id: aiResultId,
                    endpoint: `${WEBHOOK_URL}/export/${exportId}/result/${aiResultId}`,
                    verb: "POST"
                }];

                // Create an export model
                const exportModel = new CopyleaksExportModel(
                    `${WEBHOOK_URL}/export/${exportId}/completion`, // Completion webhook URL
                    results,
                    {
                        // Request to export the crawled version of the original document
                        endpoint: `${WEBHOOK_URL}/export/${exportId}/crawled-version`,
                        verb: "POST"
                    }
                );

                // Start the export process
                await copyleaks.exportAsync(loginResult, scanId, exportId, exportModel);
                console.log(`Export initiated. Export ID: ${exportId}`);

            } catch (error) {
                console.error("An error occurred:", error);
            }
        }

        exportAiDetectionResults();
      ```
      ```java title="Java" icon="java"
        import classes.Copyleaks;
        import models.exports.*;

        String scanId = "my-ai-detection-scan"; // Your scan ID from submission
        String exportId = "my-export-1"; // Your chosen export ID

        // Create headers (optional)
        String[][] headers = new String[][]{
            new String[]{"header-key", "header-value"}, 
            new String[]{"header-key-2", "header-value-2"}
        };

        // Export a specific AI detection result
        ExportResults aiResult = new ExportResults(
            "<AI_RESULT_ID_FROM_COMPLETED_WEBHOOK>", // Result ID from completed webhook
            "https://your.server/webhook/export/ai-result/1", // Endpoint URL
            "POST", // HTTP method
            headers // Optional headers
        );

        // Create array of results to export
        ExportResults[] exportResultsArray = new ExportResults[1];
        exportResultsArray[0] = aiResult;

        // Export crawled version of original document
        ExportCrawledVersion crawledVersion = new ExportCrawledVersion(
            "https://your.server/webhook/export/crawled",
            "POST",
            headers
        );

        // Create the export model
        CopyleaksExportModel exportModel = new CopyleaksExportModel(
            "https://your-server.com/webhook/export/completion", // Completion webhook
            exportResultsArray, // Results to export
            crawledVersion // Crawled version
        );

        // Execute the export with comprehensive exception handling
        try {
            Copyleaks.export(token, scanId, exportId, exportModel);
            System.out.println("Export initiated successfully.");
        } catch (ParseException e) {
            System.out.println("Parse error: " + e.getMessage());
            e.printStackTrace();
        } catch (AuthExpiredException e) {
            System.out.println("Authentication expired: " + e.getMessage());
            e.printStackTrace();
        } catch (UnderMaintenanceException e) {
            System.out.println("Service under maintenance: " + e.getMessage());
            e.printStackTrace();
        } catch (RateLimitException e) {
            System.out.println("Rate limit exceeded: " + e.getMessage());
            e.printStackTrace();
        } catch (CommandException e) {
            System.out.println("Command error: " + e.getMessage());
            e.printStackTrace();
        } catch (ExecutionException e) {
            System.out.println("Execution error: " + e.getMessage());
            e.printStackTrace();
        } catch (InterruptedException e) {
            System.out.println("Process interrupted: " + e.getMessage());
            e.printStackTrace();
        }
      ```
    </CodeGroup>
  </Step>

  <Step>
    ### Summary
    You have successfully submitted a scan for AI-generated content detection and exported the results. You can now handle the results in your application, display them to users with confidence scores and highlighted AI-generated sections, or take further actions based on the findings.
  </Step>
</Steps>

## Frequently asked questions

<AccordionGroup>
  <Accordion title="How do I enable AI detection on a scan?">
    Set `"aiGeneratedText": { "detect": true }` inside the submission `properties`. Without it, the scan runs without AI-generated text analysis.
  </Accordion>
  <Accordion title="Which file types can I scan for AI-generated content?">
    Documents such as PDF, DOCX, and TXT are supported. See the full [list of supported AI text detection file types](/reference/actions/miscellaneous/supported-ai-text-detection-file-types).
  </Accordion>
  <Accordion title="Can I test AI detection without using credits?">
    Yes. Set `"sandbox": true` in the submission properties. Sandbox mode is free and returns mock results, so you can wire up the flow before going live.
  </Accordion>
  <Accordion title="How do I know whether AI-generated content was found?">
    When the scan completes, check the `notifications.alerts` array in the webhook payload. An alert with the code `suspected-ai-text` indicates AI-generated content was detected; its `additionalData` field holds the detailed summary.
  </Accordion>
  <Accordion title="How do I get the detailed AI detection breakdown?">
    After the `completed` webhook, call the [export endpoint](/reference/actions/downloads/export) with the AI detection result ID to retrieve the [AI Detection Result](/reference/data-types/authenticity/results/ai-detection) and the [Crawled Version](/reference/data-types/authenticity/results/crawled-version) of the document.
  </Accordion>
</AccordionGroup>

## Next steps
<CardGroup cols={2}>
    <Card title="Webhooks Overview" icon="plug" href="/reference/data-types/authenticity/webhooks/overview/">Learn how to securely receive and process notifications from Copyleaks.</Card>
    <Card title="Viewing AI Detection Results" icon="browser" href="/concepts/features/how-to-display/">Understand the AI detection result format and how to display confidence scores to your users.</Card>
</CardGroup>
