Detect AI-Generated Content in Documents
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 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
Section titled “🚀 Get Started”-
Before you begin
Section titled “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.
- You can find your API key on the API Dashboard.
-
Installation
Section titled “Installation”Choose your preferred method for making API calls.
You can interact with the API using any standard HTTP client.
For a quicker setup, we provide a Postman collection. See our Postman guide for instructions.
Terminal window sudo apt-get install curlDownload it from curl.se.
Terminal window brew install curlTerminal window pip install copyleaksTerminal window npm install plagiarism-checker -
To perform a scan, we first need to generate an access token. For that, we will use the login endpoint. The API key can be found on the Copyleaks API Dashboard.
Upon successful authentication, you will receive a token that must be attached to subsequent API calls via the Authorization: Bearer
<TOKEN>
header. This token remains valid for 48 hours.POST https://id.copyleaks.com/v3/account/login/apiHeadersContent-Type: application/jsonBody{"key": "00000000-0000-0000-0000-000000000000"}Terminal window export COPYLEAKS_API_KEY="your-api-key-here"curl --request POST \--url https://id.copyleaks.com/v3/account/login/api \--header 'Accept: application/json' \--header 'Content-Type: application/json' \--data "{\"email\": \"${COPYLEAKS_EMAIL}\",\"key\": \"${COPYLEAKS_API_KEY}\"}"from copyleaks.copyleaks import CopyleaksAPI_KEY = "your-api-key-here"# Login to Copyleaksauth_token = Copyleaks.login(EMAIL_ADDRESS, API_KEY)print("Logged successfully!\nToken:", auth_token)const { Copyleaks } = require("plagiarism-checker");const API_KEY = "your-api-key-here";const copyleaks = new Copyleaks();// Login functionfunction loginToCopyleaks() {return copyleaks.loginAsync(EMAIL_ADDRESS, API_KEY).then((loginResult) => {console.log("Login successful!");console.log("Access Token:", loginResult.access_token);return loginResult;},(err) => {console.error('Login failed:', err);throw err;});}loginToCopyleaks();import com.copyleaks.sdk.api.Copyleaks;String API_KEY = "00000000-0000-0000-0000-000000000000";// Login to Copyleakstry {String authToken = Copyleaks.login(EMAIL_ADDRESS, API_KEY);System.out.println("Logged successfully!\nToken: " + authToken);} catch (CommandException e) {System.out.println("Failed to login: " + e.getMessage());System.exit(1);}Response
{"access_token": "<ACCESS_TOKEN>",".issued": "2025-07-31T10:19:40.0690015Z",".expires": "2025-08-02T10:19:40.0690016Z"} -
Submit for Scanning
Section titled “Submit for Scanning”Submission Methods
You can submit content for AI detection using multiple methods:
For this guide, we’ll demonstrate document submission. Each submission requires a unique
scanId
for proper tracking and identification.PUT https://api.copyleaks.com/v3/scans/submit/file/my-ai-detection-scanHeadersAuthorization: Bearer <YOUR_AUTH_TOKEN>Content-Type: application/jsonBody{"base64": "<BASE64_ENCODED_PDF_CONTENT>","filename": "my-file.pdf","properties": {"webhooks": {"status": "https://your-server.com/webhook/{STATUS}"},"sandbox": true,"aiGeneratedText": {"detect": true}}}Terminal window # First, encode your PDF file to base64base64_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}}}"import base64import randomfrom copyleaks.copyleaks import Copyleaksfrom copyleaks.models.submit.document import FileDocumentfrom copyleaks.models.submit.properties.scan_properties import ScanPropertiesfrom copyleaks.models.submit.properties.submit_webhooks import SubmitWebhooksfrom copyleaks.models.submit.properties.ai_generated_text import AIGeneratedTextprint("Submitting a PDF file for AI detection...")# Read and encode the PDF filewith 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 typescan_id = random.randint(100, 100000) # generate a random scan idfile_submission = FileDocument(BASE64_FILE_CONTENT, FILENAME)# Configure AI-generated text detectionai_generated_text = AIGeneratedText()ai_generated_text.detect = True # Enable AI detection# Configure webhooks for notificationswebhooks = 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 ScanPropertiesscan_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.")const { Copyleaks, CopyleaksFileSubmissionModel } = require('plagiarism-checker');const fs = require('fs');async function submitFileForAiDetection() {try {// Initialize Copyleaksconst copyleaks = new Copyleaks();// Login to get the authentication token.// Replace with your email and API key.const scanId = `ai-scan-${Date.now()}`;const WEBHOOK_URL = "https://your-server.com/webhook";// Read a file and convert it to base64const filePath = 'path/to/your/document.pdf';const fileContent = fs.readFileSync(filePath);const base64Content = fileContent.toString('base64');// Create a submission modelconst submission = new CopyleaksFileSubmissionModel(base64Content,'document.pdf',{sandbox: true, // Use sandbox for testingwebhooks: {// Copyleaks will notify this URL when the scan is complete.status: `${WEBHOOK_URL}/{STATUS}`},aiGeneratedText: {detect: true // Enable AI detection}});// Submit the file for scanningawait copyleaks.submitFileAsync(loginResult, scanId, submission);console.log(`Submission successful. Scan ID: ${scanId}`);} catch (error) {console.error("An error occurred:", error);}}submitFileForAiDetection();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 filebyte[] pdfBytes = Files.readAllBytes(Paths.get("my-file.pdf"));String base64Content = Base64.getEncoder().encodeToString(pdfBytes);// Configure webhooksSubmissionWebhooks webhooks = new SubmissionWebhooks("https://your-server.com/webhook/{STATUS}");webhooks.setNewResult("https://your-server.com/webhook/new-results");// Create submission propertiesSubmissionProperties properties = new SubmissionProperties(webhooks);properties.setSandbox(true);// Configure AI-generated text detectionSubmissionAIGeneratedText aiGeneratedText = new SubmissionAIGeneratedText();aiGeneratedText.setDetect(true);properties.setAiGeneratedText(aiGeneratedText);// Set action to scan for AI contentproperties.setAction(SubmissionActions.Scan);// Create and submit the file - Important: extension must match file typeCopyleaksFileSubmissionModel submission = new CopyleaksFileSubmissionModel(base64Content,"my-file.pdf",properties);Copyleaks.submitFile(authToken, scanId, submission);System.out.println("PDF sent to scanning..."); -
Wait for Completion Webhook
Section titled “Wait for Completion Webhook”The scan times differ depending on document length. Once it’s complete, Copyleaks will send a completed webhook to the status URL you provided.
-
Interpreting AI Detection Results
Section titled “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 detection results.
- If the array is empty or does not contain an alert with the code
-
Export Detailed Results
Section titled “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:-
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. -
Crawled Version: This is the plain text or HTML representation of the original scanned document. See the Crawled Version data type.
Your export request must specify a
completionWebhook
to be notified when the exported data is ready for download.POST https://api.copyleaks.com/v3/downloads/my-ai-detection-scan/export/<export_id>HeadersAuthorization: Bearer <your_token>Content-Type: application/jsonBody{"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"]]}]}Terminal window 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"}}]}'from copyleaks.copyleaks import Copyleaksfrom copyleaks.models.export import Export, ExportResultexport_id = "my-export-1"export = Export()export.set_completion_webhook('https://your-server.com/webhook/export/completion')# Export a specific AI detection resultresult1 = ExportResult()result1.set_id('<AI_RESULT_ID_FROM_COMPLETED_WEBHOOK>')result1.set_endpoint('https://your-server.com/webhook/export/ai-result/1') # Only URLresult1.set_verb('POST') # HTTP method separatelyexport.set_results([result1])Copyleaks.export(auth_token, scan_id, export_id, export)print("Export initiated.")const { Copyleaks, CopyleaksExportModel } = require('plagiarism-checker');async function exportAiDetectionResults() {try {// Initialize Copyleaksconst copyleaks = new Copyleaks();// Login to get the authentication token.// Replace with your email and API key.const scanId = "YOUR_SCAN_ID"; // The ID of the scan you want to exportconst exportId = `export-${scanId}-${Date.now()}`;const WEBHOOK_URL = "https://your-server.com/webhook";// The AI detection result ID to export, obtained from the completion webhookconst aiResultId = "AI_RESULT_ID_FROM_WEBHOOK";const results = [{id: aiResultId,endpoint: `${WEBHOOK_URL}/export/${exportId}/result/${aiResultId}`,verb: "POST"}];// Create an export modelconst exportModel = new CopyleaksExportModel(`${WEBHOOK_URL}/export/${exportId}/completion`, // Completion webhook URLresults,{// Request to export the crawled version of the original documentendpoint: `${WEBHOOK_URL}/export/${exportId}/crawled-version`,verb: "POST"});// Start the export processawait copyleaks.exportAsync(loginResult, scanId, exportId, exportModel);console.log(`Export initiated. Export ID: ${exportId}`);} catch (error) {console.error("An error occurred:", error);}}exportAiDetectionResults();import classes.Copyleaks;import models.exports.*;String scanId = "my-ai-detection-scan"; // Your scan ID from submissionString 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 resultExportResults 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 methodheaders // Optional headers);// Create array of results to exportExportResults[] exportResultsArray = new ExportResults[1];exportResultsArray[0] = aiResult;// Export crawled version of original documentExportCrawledVersion crawledVersion = new ExportCrawledVersion("https://your.server/webhook/export/crawled","POST",headers);// Create the export modelCopyleaksExportModel exportModel = new CopyleaksExportModel("https://your-server.com/webhook/export/completion", // Completion webhookexportResultsArray, // Results to exportcrawledVersion // Crawled version);// Execute the export with comprehensive exception handlingtry {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();} -
-
🎉Congratulations!
Section titled “🎉Congratulations!”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.