API Documentation
ISO 27001SOC 2 CertifiedGDPR Compliant

AI Text Detection API

Complete documentation for integrating TruthScan's AI detection API into your applications.

Try it out without code by visiting our FastAPI endpoint: https://detect-text.truthscan.com/docs

Authentication

TruthScan 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.

TruthScan 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"
}

You must replace YOUR API KEY GOES HERE with your personal API key.

For web socket scenarios, you will need to send your Organization ID as part of the url. You can get your Organization ID at the top of the page in our developer portal.

TruthScan expects your Organization ID to be included in the url of all web socket requests. The documentation will look like the following:

wss://detect-text.truthscan.com/ws/$ORG_ID

You must replace $ORG_ID with your personal Organization ID.

AI Detector

Detect

This endpoint allows you to submit text for AI detection. At least 200 words are recommended for best accuracy.

POST https://detect-text.truthscan.com/detect

Threshold

This endpoint returns a "result" score from 1-100. For best accuracy, any score under 50 is considered definitely human. 50-60 is possible AI. Over 60 is definite AI. This is the most accurate result, with 99%+ accuracy.

The scores for other detectors, such as Writer and Copyleaks, are approximate and not as accurate as the main "result" score.

Line breaks

If you're sending data as JSON, line breaks should be encoded as \n inside the string.

Example Request

curl -X 'POST' \
  'https://detect-text.truthscan.com/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,
  "generate_analysis_details": true
}'

Here, the request input must be less than 30,000 words.

Optional Parameters

  • model: AI detection model to use (default: 'xlm_ud_detector')
  • retry_count: Number of retries if processing fails (default: 0)
  • generate_analysis_details: Set to 'true' to enable deep AI analysis results (default: 'false'). When enabled, the query response will include analysis_results_status and analysis_results fields.

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.

POST https://detect-text.truthscan.com/query

Example Request

curl -X 'POST' \
  'https://detect-text.truthscan.com/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,
    "label": "Human",
    "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,
        "analysis_results_status": "pending",
        "analysis_results": null
    },
    "result_categories": {
        "advanced": 12,
        "standard": 12
    },
    "status": "done",
    "retry_count": 0
}

Result Interpretation

  • result: Score from 0-100 indicating the likelihood the text is AI-generated. Under 50 = definitely human. 50-60 = possible AI. Over 60 = definite AI.
  • label: The overall determination: 'Human', 'AI', or 'Paraphrase'
  • result_details scores: Approximate scores from third-party detectors: GPTZero, OpenAI, Writer, CrossPlag, CopyLeaks, Sapling, ContentAtScale, ZeroGPT (each 0, 50, or 100)
  • human: Average of all third-party detector scores indicating how human the text appears
  • result_categories.advanced: Advanced result category with tiered scoring (1-99 formatted)
  • result_categories.standard: Standard result category
  • analysis_results_status: Status of deep AI analysis ('pending', 'ready', 'skipped', or null). When 'pending', continue polling the /query endpoint — analysis is still processing in the background. When 'ready', the analysis_results field contains the completed analysis. When 'skipped', null, or absent, deep analysis is not available for this text.
  • analysis_results: Deep AI analysis results (available when analysis_results_status is 'ready'). Contains: agreement (strong/moderate/weak/disagreement), confidence (0-100), keyIndicators (array of textual indicators found), detailedReasoning (explanation), linguisticPatterns (array of linguistic patterns observed), and recommendations (actionable items).

Here, "result": 12.0 indicates the human-ness of the input. This means that given it is less than the 50% threshold, the text is definitely human. 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.

GET https://detect-text.truthscan.com/check-user-credits

Example Request

curl -X 'GET' \
  'https://detect-text.truthscan.com/check-user-credits' \
  -H 'apikey: YOUR API KEY GOES HERE' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json'

Example Response

{
    "baseCredits": 10000,
    "boostCredits": 1000,
    "credits": 11000
}

Analysis Results (Asynchronous Deep Analysis)

When you set 'generate_analysis_details' to 'true' in the /detect request, TruthScan runs a deep AI analysis in the background after the initial detection completes. The initial query response will return with status 'done' and your detection results ready to use, but the analysis_results_status field may still be 'pending'. You can use the initial results immediately and optionally poll for the deep analysis to complete.

1. Initial Result Settles (Analysis Still Pending)

When you submit with 'generate_analysis_details': true and first query with status 'done', the core detection results (result, label, result_details) are ready. However, analysis_results_status may be 'pending' — this means the deep AI analysis is still processing in the background.

{
    "id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
    "model": "xlm_ud_detector",
    "status": "done",
    "result": 73.2,
    "label": "AI",
    "result_details": {
        "scoreGptZero": 100.0,
        "scoreOpenAI": 50.0,
        "scoreWriter": 50.0,
        "scoreCrossPlag": 100.0,
        "scoreCopyLeaks": 100.0,
        "scoreSapling": 50.0,
        "scoreContentAtScale": 50.0,
        "scoreZeroGPT": 100.0,
        "human": 25.0,
        "analysis_results_status": "pending",
        "analysis_results": null
    }
}

What to do

You can use the initial detection results (result, label, result_details scores) immediately. If you also need the deep analysis, continue polling the /query endpoint with the same document ID until analysis_results_status changes from 'pending'.

2. Keep Polling for Analysis Results

Continue calling the /query endpoint with the same document ID. Check the analysis_results_status field on each response. When it changes from 'pending' to 'ready', the analysis_results object will be populated.

curl -X 'POST' \
  'https://detect-text.truthscan.com/query' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "id": "77565038-9e3d-4e6a-8c80-e20785be5ee9"
}'

3. Analysis Complete — Full Response

Once analysis_results_status is 'ready', the analysis_results object contains the full deep AI analysis with agreement level, confidence, key indicators, detailed reasoning, linguistic patterns, and recommendations.

{
    "id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
    "model": "xlm_ud_detector",
    "status": "done",
    "result": 73.2,
    "label": "AI",
    "result_details": {
        "scoreGptZero": 100.0,
        "scoreOpenAI": 50.0,
        "scoreWriter": 50.0,
        "scoreCrossPlag": 100.0,
        "scoreCopyLeaks": 100.0,
        "scoreSapling": 50.0,
        "scoreContentAtScale": 50.0,
        "scoreZeroGPT": 100.0,
        "human": 25.0,
        "analysis_results_status": "ready",
        "analysis_results": {
            "agreement": "strong",
            "confidence": 78,
            "keyIndicators": [
                "Highly consistent sentence structure throughout",
                "Formulaic transitions between paragraphs",
                "Lack of personal voice or idiosyncratic expressions"
            ],
            "detailedReasoning": "The text exhibits hallmarks of AI-generated content including uniform sentence complexity, predictable paragraph transitions, and an absence of personal stylistic quirks. The vocabulary choices are sophisticated but lack the natural variation typical of human writing.",
            "linguisticPatterns": [
                "Uniform sentence length distribution",
                "Repetitive use of hedging language",
                "Absence of colloquialisms or informal markers"
            ],
            "recommendations": [
                "Cross-reference with the original source if available",
                "Check for consistent writing style across longer documents",
                "Compare with known writing samples from the claimed author",
                "Consider the context in which the text was produced"
            ]
        }
    },
    "result_categories": {
        "advanced": 73,
        "standard": 73
    }
}

When Analysis Is Not Available

If analysis_results_status is 'skipped', null, or absent, deep analysis will not be produced for this text. This happens when 'generate_analysis_details' was not set to 'true' in the /detect request, or for certain processing scenarios. You should treat the initial detection results as final.

{
    "status": "done",
    "result": 12.0,
    "label": "Human",
    "result_details": {
        "analysis_results_status": "skipped",
        "analysis_results": null
    }
}

Analysis Results Fields

  • analysis_results_status: 'pending' = still processing, 'ready' = results available, 'skipped' / null / absent = not available for this text
  • analysis_results.agreement: How strongly the deep analysis agrees with the initial detection (strong / moderate / weak / disagreement)
  • analysis_results.confidence: Confidence score of the deep analysis (0-100)
  • analysis_results.keyIndicators: Array of specific textual indicators found in the text
  • analysis_results.detailedReasoning: 2-4 sentence explanation of why the text was classified this way
  • analysis_results.linguisticPatterns: Array of linguistic patterns observed (e.g., sentence structure consistency, vocabulary patterns)
  • analysis_results.recommendations: Array of actionable recommendations for understanding the text's authenticity

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

Connect to the WebSocket

This endpoint allows you to establish the WebSocket connection

wss://detect-text.truthscan.com/ws/$ORG_ID

Example code

ws = new WebSocket("wss://detect-text.truthscan.com/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

POST https://detect-text.truthscan.com/detect

Example Request

curl -X 'POST' \
  'https://detect-text.truthscan.com/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": "xlm_ud_detector",
  "id": "512da191-166926922-44cb-81c6-191ae3a807aa"
}'

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": "xlm_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": "xlm_ud_detector"
}

Handling exceptional circumstances

If for some reason the server encounters an error while performing AI detection, 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"
}

Errors

Most errors will be from incorrect parameters being sent to the API. Double check the parameters of each API call to make sure it's properly formatted, and try running the provided example code.

The generic error codes we use conform to the REST standard:

Error CodeMeaning
400Bad Request -- Your request is invalid.
403Forbidden -- The API key is invalid, or there aren't sufficient credits (0.1 per word).
404Not Found -- The specified resource doesn't exist.
405Method Not Allowed -- You tried to access a resource with an invalid method.
406Not Acceptable -- You requested a format that isn't JSON.
410Gone -- The resource at this endpoint has been removed.
422Invalid Request Body -- Your request body is formatted incorrectly or invalid or has missing parameters.
429Too Many Requests -- You're sending too many requests! Slow it down!
500Internal Server Error -- We had a problem with our server. Try again later.
503Service 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:

  1. Verify your API key is correct
  2. Check if your API key is active in your account
  3. Try regenerating your API key

"Not enough credits" (403)

Cause: Insufficient credits for text processing

Solution:

  1. Check your remaining credits using /check-user-credits
  2. Purchase additional credits if needed
  3. 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:

  1. Ensure your text input is not empty
  2. Remove any leading/trailing whitespace
  3. Check if text encoding is correct

"Input email is empty" (400)

Cause: Missing email for URL processing

Solution:

  1. Provide a valid email address when submitting URLs
  2. Check email format is correct

Processing Issues

"Request timeout" (WebSocket)

Cause: Document processing took too long (>120 seconds)

Solution:

  1. Try with a smaller text input
  2. Check if the service is experiencing high load
  3. Retry the request

Document Status "failed"

Cause: Processing failed for various reasons

Solution:

  1. Check if input text meets minimum requirements
  2. Verify text is in a supported format
  3. Try with a different model
  4. Contact support if issue persists

WebSocket Connection Issues

Connection Drops

Cause: Network issues or server disconnects

Solution:

  1. Check your network connection
  2. Implement reconnection logic
  3. Verify WebSocket URL is correct

"User not found" (WebSocket)

Cause: Invalid Organization ID in WebSocket connection

Solution:

  1. Verify Organization ID is correct
  2. Ensure user account is active
  3. Re-authenticate if needed

Need Help?

For more information about using our API or for technical support, please contact us.

API Frequently Asked Questions

Find answers to the most common questions about our AI detection API.