Detector API
Try it Out
You can test out the API without code by going to the FastAPI link with your web browser: https://ai-detect.undetectable.ai/docs
Authentication
Undetectable.AI uses API keys to allow access to the API. You can get your API key at the top of the page in our developer portal.
UD expects for the API key to be included in all API requests to the server in a request body that looks like the following:
key: YOUR API KEY GOES HERE
YOUR API KEY GOES HERE with your personal API key.For web socket scenarios, you will need to send the users id as part of the url. You can get your User ID at the top of the page in our developer portal.
UD expects for the users User ID to be included in the url of all web socket requests. The documentation will look like the following:
https://ai-detect.undetectable.ai/ws/$USER_ID$USER_ID with your personal User Id.AI Detector
Detect
This endpoint allows you to submit text for AI detection. At least 200 words are recommended for best accuracy.
https://ai-detect.undetectable.ai/detectOn Citizen science
Citizen science involves the public participating in scientific research. This can take many forms, collecting data on local wildlife populations to analyzing astronomical images. Citizen science projects allow researchers to gather large amounts of data and engage the public in the process. By participating, individuals contribute to valuable research while gaining a deeper understanding of the scientific world around them.
Example Request
curl -X 'POST' \
'https://ai-detect.undetectable.ai/detect' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"text": "On Citizen science\nCitizen science involves the public participating in scientific research. This can take many forms, collecting data on local wildlife populations to analyzing astronomical images. Citizen science projects allow researchers to gather large amounts of data and engage the public in the process. By participating, individuals contribute to valuable research while gaining a deeper understanding of the scientific world around them.",
"key": "YOUR-API-KEY-GOES-HERE",
"model": "xlm_ud_detector",
"retry_count": 0
}'
Here, the request input must be less than 30,000 words.
Example Response
{
"id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
"input": "Citizen science involves the public participating in scientific research. This can take many forms, collecting data on local wildlife populations to analyzing astronomical images. Citizen science projects allow researchers to gather large amounts of data and engage the public in the process. By participating, individuals contribute to valuable research while gaining a deeper understanding of the scientific world around them.",
"model": "xlm_ud_detector",
"result": null,
"result_details": null,
"status": "pending",
"retry_count": 0
}
The response contains the server-assigned ID of the document. At this point the document is now enqueued for processing. You can use the /query API endpoint to query the status of the AI Detection request. The average time to complete an AI Detection check is between 2-4 seconds. It may take longer depending on word count.
Query
This endpoint accepts a document id returned by the /detect request. And returns the status of the document submission as well as the result of the AI Detection operation as handled by various third-party AI detectors.
https://ai-detect.undetectable.ai/queryExample Request
curl -X 'POST' \
'https://ai-detect.undetectable.ai/query' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": "DOCUMENT-ID-GOES-HERE"
}'
Example Response
{
"id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
"model": "xlm_ud_detector",
"result": 12.0,
"result_details": {
"scoreGptZero": 50.0,
"scoreOpenAI": 0.0,
"scoreWriter": 0.0,
"scoreCrossPlag": 0.0,
"scoreCopyLeaks": 50.0,
"scoreSapling": 0.0,
"scoreContentAtScale": 0.0,
"scoreZeroGPT": 50.0,
"human": 88.0
},
"status": "done",
"retry_count": 0
}
Here, "result": 88.0 indicates the AI-ness of the input. This means that given it is greater than the 50% threshold, the text is AI-generated. Similarly the values under the result_details indicate the Human-ness of the input. For example "scoreZeroGPT": 50.0 signifies that the text is likely 50% human-written as per ZeroGPT. The Same goes for the rest of the other detectors.
Check User Credits
This endpoint accepts the users apikey via the header. And returns users credit details.
https://ai-detect.undetectable.ai/check-user-creditsExample Request
curl -X 'POST' \
'https://ai-detect.undetectable.ai/query' \
-H 'apikey: YOUR API KEY GOES HERE' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
Example Response
{
"baseCredits": 10000,
"boostCredits": 1000,
"credits": 11000
}
Sentence Level AI Detection
The sentence-level AI Detector runs on top of a WebSocket-based protocol.
Here are the necessary steps needed to get sentence-level results for your text.
- Connect to the WebSocket
- Listen for all events received from the WebSocket
- Send a document_watch request
- Receive a document_id event
- Take the id generated by the document_id response and submit a document for AI Detection
- Start receiving document_chunk events. document_chunk events will return each sentence together with the sentence-level result
- When the document finishes processing, you will receive a document_done event.
This section will describe the necessary steps to connect, send a document for processing, and listen to the sentence stream until it finishes.
Connect to the WebSocket
This endpoint allows you to establish the WebSocket connection
https://ai-detect.undetectable.ai/ws/$USER_IDExample code:
ws = new WebSocket("wss://https://ai-detect.undetectable.ai/ws/1722238709737x2194626580942121212");
Listen for all events received from the WebSocket
Once the WebSocket connection is established, listen to events sent through the WebSocket connection.
Example code:
ws.addEventListener("message", (event) => {
console.log("Message from server ", event.data);
});
Send a document_watch request
Send interest in sending a document by sending a document_watch request on the WebSocket
Example code:
ws.send(JSON.stringify({
"event_type": "document_watch",
"api_key": "$API_KEY",
}))
Receive a document_id event
After sending a document_watch event, the server returns a document_id event.
Example response:
{
"event_type": "document_id",
"success": true,
"document_id": "512da191-166926922-44cb-81c6-191ae3a807aa"
}Submit an AI Detection Request
Take the id generated by the document_id response and submit a document for AI Detection
https://ai-detect.undetectable.ai/detectExample Request
curl -X 'POST' \
'https://ai-detect.undetectable.ai/detect' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"text": "Citizen science involves the public participating in scientific research. This can take many forms, collecting data on local wildlife populations to analyzing astronomical images. Citizen science projects allow researchers to gather large amounts of data and engage the public in the process. By participating, individuals contribute to valuable research while gaining a deeper understanding of the scientific world around them.",
"key": "YOUR-API-KEY-GOES-HERE",
"model": "xIm_ud_detector",
"id": "512da191-166926922-44cb-81c6-191ae3a807aa"
}'
Example Response
{
"id": "512da191-166926922-44cb-81c6-191ae3a807aa",
"input": "Citizen science involves the public participating in scientific research. This can take many forms, collecting data on local wildlife populations to analyzing astronomical images. Citizen science projects allow researchers to gather large amounts of data and engage the public in the process. By participating, individuals contribute to valuable research while gaining a deeper understanding of the scientific world around them.",
"model": "xIm_ud_detector",
"result": null,
"result_details": null,
"status": "pending",
"retry_count": 0
}
Receive sentence level results
Start receiving document_chunk events. document_chunk events will return each sentence together with the sentence level result
Example responses:
{
"event_type": "document_chunk",
"document_id": "512da191-166926922-44cb-81c6-191ae3a807aa"
"model": "xIm_ud_detector",
"chunk": "Citizen science involves the public in scientific research.",
"result": 0.714
}When the document finishes processing, you will receive a document_done event.
Example responses:
{
"event_type": "document_done",
"document_id": "512da191-166926922-44cb-81c6-191ae3a807aa"
"model": "xIm_ud_detector"
}Below is an example sequence as returned by the WS stream.

Handling exceptional circumstances
If for some reason the server encounters an error while doing the humanization, a document_error event will be sent to the websocket client. The client should act as appropriate, for example a UI will show an error message.
For example, the server will send a REQUEST_TIMEOUT error code when it takes more than 20 seconds across chunk events.
{
"event_type": "document_error",
"document_id": "512da191-166926922-44cb-81c6-191ae3a807aa"
"error_code": "REQUEST_TIMEOUT",
"message": "Request timeout. Took 20 seconds.",
}Cancellations
There will be instances when the UI would want to cancel the operation. The user decides to close the window, or cancels the event explicitly
When this happens you should sent a document_halt event
Example responses:
{
"event_type": "document_halt",
"document_id": "512da191-166926922-44cb-81c6-191ae3a807aa"
}PDF Detector
The PDF Detector analyzes uploaded PDF files asynchronously. PDFs must be uploaded to object storage first, then submitted via /detect-pdf. Poll /query until status is done.
Three detector versions are available. Each answers a different question — pick the one that matches your use case (or run both v1 and v3/v4 on the same file by submitting twice with different model values):
pdf_detector/v1Detects whether the PDF was generated by an AI tool using rule-based fingerprints in PDF metadata (/Creator, /Producer). Example hits: "ChatGPT", "Grok", or generic "AI Generated".pdf_detector/v3Detects whether the PDF was edited or tampered with after creation and whether it carries AI-generation traits. Checks for overlays, hidden text, font anomalies, post-creation content changes, and signs of AI-generated documents. Includes a natural-language llm_explanation.v4 : pdf_detector/v4 (default / latest)Same tampering analysis as v3 with improved accuracy. Uses AI to reduce common false positives before returning results. Includes llm_explanation. The response format matches v3.v2 deprecationpdf_detector/v2 is accepted for backward compatibility and runs the latest version (v4).model, or send "pdf_detector", to use the latest version (currently pdf_detector/v4).Send "model": "pdf_detector/v1" for AI-generation metadata detection.Send "model": "pdf_detector/v3" to pin v3.Send "model": "pdf_detector/v4" to pin v4 explicitly.Any other model value returns 400 Bad Request.GET /get-presigned-url with a .pdf file name and your API key in the apikey header.PUT the PDF bytes to the returned presigned_url.POST /detect-pdf with the public object url, your API key, and an optional model.POST /query with the returned document id until processing completes..pdf, at most 2 MB, and reachable at the url you submit./check-user-credits before submitting large documents.result is 100.0 when the detector flags a hit and 0.0 when it does not. This is not the 0–100 AI-likeness scale used by text detection (xlm_ud_detector). The 50/60 human/AI thresholds apply only to text /detect.Obtain a Pre-signed Upload URL
Request a presigned upload URL before submitting a PDF for detection.
https://ai-detect.undetectable.ai/get-presigned-urlapikey header.Example Request
curl -X 'GET' \
'https://ai-detect.undetectable.ai/get-presigned-url?file_name=report.pdf&expiration=3600' \
-H 'accept: application/json' \
-H 'apikey: YOUR-API-KEY-GOES-HERE'
Upload the file with a PUT to the presigned_url from the response before calling /detect-pdf.
Example Response
{
"status": "success",
"presigned_url": "https://...digitaloceanspaces.com/...?X-Amz-Algorithm=...",
"file_path": "userId_20250604120000_report.pdf"
}
Upload the PDF
Use the provided presigned_url to upload your PDF via a PUT request.
Example Request
curl -X PUT 'https://nyc3.digitaloceanspaces.com/ai-detector-prod/uploads/581d47c7-3ef4-42af-88d9-6dab6bf69389_20250611-121955_report.pdf...' \
--header 'Content-Type: application/pdf' \
--header 'x-amz-acl: private' \
--data-binary '@report.pdf'
Detect PDF
Submit a PDF that has already been uploaded to object storage.
https://ai-detect.undetectable.ai/detect-pdfurl (required) : public object-storage URL of the uploaded PDF.key (required) : your API key.model (optional) : pdf_detector/v1, pdf_detector/v2 (forwards to v4), pdf_detector/v3, pdf_detector/v4, or pdf_detector (latest). Defaults to pdf_detector/v4.Example Request : default (v4 / latest)
curl -X 'POST' \
'https://ai-detect.undetectable.ai/detect-pdf' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://your-bucket.region.digitaloceanspaces.com/userId_20250604120000_report.pdf",
"key": "YOUR-API-KEY-GOES-HERE"
}'
Example Request : pin to v1 (AI-generation metadata)
curl -X 'POST' \
'https://ai-detect.undetectable.ai/detect-pdf' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://your-bucket.region.digitaloceanspaces.com/userId_20250604120000_report.pdf",
"key": "YOUR-API-KEY-GOES-HERE",
"model": "pdf_detector/v1"
}'
Example Response
{
"id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
"model": "pdf_detector/v3",
"result": null,
"result_details": null,
"status": "pending",
"retry_count": 0
}
The response contains the server-assigned document ID. Use POST /query to poll for results. Typical completion time is a few seconds.
Query
Poll PDF detection status and results by document ID (same endpoint as text detection). Response shape depends on which model was used for the job.
https://ai-detect.undetectable.ai/queryExample Request
curl -X 'POST' \
'https://ai-detect.undetectable.ai/query' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": "DOCUMENT-ID-GOES-HERE"
}'
Example Response: v1 AI fingerprint found
{
"id": "077eaa29-db75-4266-8eae-8a49d41c25ad",
"model": "pdf_detector/v1",
"status": "done",
"result": 100.0,
"label": "Tampering Detected",
"result_details": {
"prediction": "Grok",
"base_category": "Possibly AI Generated/Edited"
},
"result_categories": null,
"source_details": {
"source": "Grok",
"confidence": null,
"credits_deducted": null
},
"retry_count": 0
}
result: 100.0 if an AI-generation fingerprint was found; 0.0 if not.label: "Tampering Detected" when flagged; "No Tampering Detected" otherwise.result_details.prediction: specific tool name (e.g. "Grok", "ChatGPT"), generic "AI Generated", or "No Tampering Detected".result_details.base_category: "Possibly AI Generated/Edited" or "No Tampering Detected".source_details.source: attributed source on a hit; null when no fingerprint is found.Example Response: v1 no AI fingerprint
{
"id": "077eaa29-db75-4266-8eae-8a49d41c25ad",
"model": "pdf_detector/v1",
"status": "done",
"result": 0.0,
"label": "No Tampering Detected",
"result_details": {
"prediction": "No Tampering Detected",
"base_category": "No Tampering Detected"
},
"result_categories": null,
"source_details": null,
"retry_count": 0
}
Example Response: v3 structural tampering detected
{
"id": "5395e0d8-41d6-4e30-add7-97b8a7ffbbc9",
"model": "pdf_detector/v3",
"status": "done",
"result": 100.0,
"label": "Tampered",
"result_details": {
"status": "ok",
"structure": {
"prediction": "Tampered",
"rule": { "revision": "high" },
"max_severity": "high",
"signals_flagged": 1,
"signals": {
"overlay": { "label": "Overlay / Annotation Layer", "flagged": false, "severity": null, "findings": [] },
"hidden": { "label": "Hidden Text", "flagged": false, "severity": null, "findings": [] },
"font": { "label": "Font Anomalies", "flagged": false, "severity": null, "findings": [] },
"revision": {
"label": "Incremental / Revision Tampering",
"flagged": true,
"severity": "high",
"findings": [
{
"severity": "high",
"detail": "Page content overwritten after creation.",
"changes": ["p1: '$1,250.00' -> '$5,750.00'"]
}
]
},
"ai_origin": { "label": "AI Origin", "flagged": false, "severity": null, "findings": [] }
}
},
"llm_explanation": "The amount on page 1 was changed from $1,250.00 to $5,750.00 after the document was created."
}
}
Example Response: v3 AI-generated (engine marker escalation)
{
"id": "5395e0d8-41d6-4e30-add7-97b8a7ffbbc9",
"model": "pdf_detector/v3",
"status": "done",
"result": 100.0,
"label": "Tampered",
"result_details": {
"status": "ok",
"structure": {
"prediction": "Tampered",
"rule": { "ai_origin": "high" },
"max_severity": "high",
"signals_flagged": 1,
"signals": {
"overlay": { "label": "Overlay / Annotation Layer", "flagged": false, "severity": null, "findings": [] },
"hidden": { "label": "Hidden Text", "flagged": false, "severity": null, "findings": [] },
"font": { "label": "Font Anomalies", "flagged": false, "severity": null, "findings": [] },
"revision": { "label": "Incremental / Revision Tampering", "flagged": false, "severity": null, "findings": [] },
"ai_origin": {
"label": "AI Origin",
"flagged": true,
"severity": "high",
"findings": [
{
"severity": "high",
"detail": "Document carries an AI-generation engine marker."
}
]
}
}
},
"llm_explanation": "This document was generated by an AI tool."
}
}
Example Response: v3 no tampering detected (Genuine)
{
"id": "5395e0d8-41d6-4e30-add7-97b8a7ffbbc9",
"model": "pdf_detector/v3",
"status": "done",
"result": 0.0,
"label": "Genuine",
"result_details": {
"status": "ok",
"structure": {
"prediction": "Genuine",
"rule": {},
"max_severity": null,
"signals_flagged": 0,
"signals": {
"overlay": { "label": "Overlay / Annotation Layer", "flagged": false, "severity": null, "findings": [] },
"hidden": { "label": "Hidden Text", "flagged": false, "severity": null, "findings": [] },
"font": { "label": "Font Anomalies", "flagged": false, "severity": null, "findings": [] },
"revision": { "label": "Incremental / Revision Tampering", "flagged": false, "severity": null, "findings": [] },
"ai_origin": { "label": "AI Origin", "flagged": false, "severity": null, "findings": [] }
}
},
"llm_explanation": "No AI-generation or tampering fingerprints were detected; the PDF looks clean."
}
}
Example Response: v4 (same format as v3)
v4 returns the same response shape as v3. The model field will show pdf_detector/v4.
result: 100.0 when tampering or suspicious signals are detected; 0.0 when none are found.label: mirrors structure.prediction : "Tampered", "Suspicious", or "Genuine".result_details.structure.signals: breakdown by signal type (overlay, hidden, font, revision, ai_origin). Each includes label, flagged, severity, and findings (with optional changes showing before/after values when available).result_details.llm_explanation: plain-language summary of the findings.overlay : Editing marks or boxes layered on top of the original content (white-outs, stamps, added text).hidden : Text that is invisible, off-page, or clipped from view.font : Mismatched fonts suggesting a value was retyped or replaced.revision : Content changed after the PDF was originally created (may include exact before/after values).ai_origin : Signs the document was created by an AI tool."Tampered" : strong evidence of content manipulation or AI-generated origin."Suspicious" : one or more signals detected, but none at the highest confidence level."Genuine" : no tampering signals detected."low", "medium", or "high" to indicate confidence.Errors
The generic error codes we use conform to the REST standard:
Error Code | Meaning |
|---|---|
400 | Bad Request -- Your request is invalid. |
403 | Forbidden -- The API key is invalid, or there aren't sufficient credits (0.1 per word). |
404 | Not Found -- The specified resource doesn't exist. |
405 | Method Not Allowed -- You tried to access a resource with an invalid method. |
406 | Not Acceptable -- You requested a format that isn't JSON. |
410 | Gone -- The resource at this endpoint has been removed. |
422 | Invalid Request Body -- Your request body is formatted incorrectly or invalid or has missing parameters. |
429 | Too Many Requests -- You're sending too many requests! Slow it down! |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
Common Issues and Solutions
Authentication Issues
"User verification failed" (403)
- Cause: Invalid or expired API key
- Solution:
- Verify your API key is correct
- Check if your API key is active in your account
- Try regenerating your API key
"Not enough credits" (403)
- Cause: Insufficient credits for text processing
- Solution:
- Check your remaining credits using
/check-user-credits - Purchase additional credits if needed
- Use shorter text inputs to consume fewer credits
Input Validation Issues
"Input text cannot be empty" (400)
- Cause: Empty or whitespace-only text submitted
- Solution:
- Ensure your text input is not empty
- Remove any leading/trailing whitespace
- Check if text encoding is correct
"Input email is empty" (400)
- Cause: Missing email for URL processing
- Solution:
- Provide a valid email address when submitting URLs
- Check email format is correct
Processing Issues
"Request timeout" (WebSocket)
- Cause: Document processing took too long (>120 seconds)
- Solution:
- Try with a smaller text input
- Check if the service is experiencing high load
- Retry the request
Document Status "failed"
- Cause: Processing failed for various reasons
- Solution:
- Check if input text meets minimum requirements
- Verify text is in a supported format
- Try with a different model
- Contact support if issue persists
WebSocket Connection Issues
Connection Drops
- Cause: Network issues or server disconnects
- Solution:
- Check your network connection
- Implement reconnection logic
- Verify WebSocket URL is correct
"User not found" (WebSocket)
- Cause: Invalid user ID in WebSocket connection
- Solution:
- Verify user ID is correct
- Ensure user account is active
- Re-authenticate if needed
Updated on: 13/07/2026
Thank you!
