API Documentation
ISO 27001SOC 2 CertifiedGDPR Compliant

AI Image Detection API

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

Try it out without code by visiting our FastAPI endpoint: https://detect-image.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 the API key to be included in API requests to the server in a JSON body like the following (unless an endpoint documents header-only auth, e.g. check-user-credits):

{
  "key": "YOUR API KEY GOES HERE"
}

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

AI Image Detector

Detect (3-Step Process)

The AI Image Detection workflow consists of the following steps:

  • Obtain a Pre-signed Upload URL
  • Upload the Image
  • Submit the Image for Detection

1. Obtain a Pre-signed Upload URL

Begin by requesting a pre-signed URL from the API. This URL allows you to securely upload your image file to the storage server.

Supported File Formats

JPG, JPEG, PNG, WebP, JFIF, HEIC, HEIF, AVIF, BMP, TIFF, TIF, GIF, SVG, PDF

Filename

Remove spaces from the image filename when requesting a pre-signed URL.

For PDF files, only the first image will be detected (single-file flow).

Use a .zip filename on this endpoint when you intend to submit a ZIP via bulk upload.

Query parameters

  • file_name (required) — Original filename; the server may normalize it (spaces and unsafe characters are adjusted). Use a .zip extension for bulk upload.
  • expiration (optional) — Presigned URL lifetime in seconds (default: 3600).
GET https://detect-image.truthscan.com/get-presigned-url?file_name=example.jpg

Example Request

curl -X GET 'https://detect-image.truthscan.com/get-presigned-url?file_name=example.jpg' \
--header 'apikey: YOUR API KEY GOES HERE'

Example Response

{
  "status": "success",
  "presigned_url": "https://nyc3.digitaloceanspaces.com/ai-image-detector-dev/uploads/581d47c7-3ef4-42af-88d9-6dab6bf69389_20250611-121955_example.jpg...",
  "file_path": "uploads/example.jpg",
  "document_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

The document_id is a new UUID generated for this upload request (for correlation/logging). The id you use for /detect or /bulk-upload is assigned when you submit those endpoints unless you pass an optional id on /detect.

2. Upload the Image

Use the provided presigned_url to upload your image via a PUT request. Ensure the correct Content-Type is set according to your image format.

Filename

Remove spaces from the image filename when uploading the image.

Set Content-Type to match your file extension exactly

  • image/jpeg: jpg, jpeg, jfif
  • image/png: png
  • image/webp: webp
  • image/heic: heic
  • image/heif: heif
  • image/avif: avif
  • image/bmp: bmp
  • image/tiff: tiff, tif
  • image/gif: gif
  • image/svg+xml: svg
  • application/pdf: pdf

Common mistakes to avoid

  • Do not use image/jpg (incorrect). Use image/jpeg.
  • Do not mismatch file and header (e.g., .png file with image/jpeg).
  • Do not change the extension without updating the header (or vice versa).
  • Do not include spaces in filenames when requesting/uploading.

Example Request

curl -X PUT 'https://nyc3.digitaloceanspaces.com/ai-image-detector-dev/uploads/581d47c7-3ef4-42af-88d9-6dab6bf69389_20250611-121955_example.jpg...' \
  --header 'Content-Type: image/jpeg' \
  --header 'x-amz-acl: private' \
  --data-binary '@example.jpg'

Additional upload examples (PNG, PDF, SVG)

curl -X PUT '<PRESIGNED_URL_FOR_example.png>' \
  --header 'Content-Type: image/png' \
  --header 'x-amz-acl: private' \
  --data-binary '@example.png'
curl -X PUT '<PRESIGNED_URL_FOR_example.pdf>' \
  --header 'Content-Type: application/pdf' \
  --header 'x-amz-acl: private' \
  --data-binary '@example.pdf'
curl -X PUT '<PRESIGNED_URL_FOR_example.svg>' \
  --header 'Content-Type: image/svg+xml' \
  --header 'x-amz-acl: private' \
  --data-binary '@example.svg'

File Size Limits

  • Minimum file size: 1KB
  • Maximum file size: 10MB

Ensure that the file format remains consistent during the upload process. A successful upload returns HTTP 200.

3. Submit Image for AI Detection

After uploading, submit the image for AI detection by referencing the file_path from the previous step. For PDF uploads, only the first image will be analyzed/detected.

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

Example Request

curl -X 'POST' \
  'https://detect-image.truthscan.com/detect' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "key": "YOUR-API-KEY-GOES-HERE",
  "url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/<FILE_PATH>",
  "generate_preview": true
}'

The FILE_PATH refers to the path returned from the presigned-URL step (e.g. uploads/...). Build the full URL with your storage host as shown in the example.

Optional Parameters

  • id: Optional UUID string. If omitted, the server generates a new document id. If provided, it must not already exist; otherwise the API returns an error.
  • generate_preview: Set to true to generate a preview URL for the image (default: true). Set to false to skip preview generation.
  • document_type: Type of document (default: Image).
  • email: Email address for processing.
  • generate_analysis_details: Set to false to skip generating detailed analysis (default: true).
  • generate_heatmap_overlayed: Controls how the heatmap image is produced when a heatmap is generated (default: true). When true, the heatmap is blended onto the original image (standard overlay). When false, the service returns a transparent heatmap: an RGBA image with the JET-colored activation map and alpha from the model, with a transparent background so you can composite it in your UI.
  • generate_heatmap_normalized: When false, heatmap generation skips the normalization step used for the activation map (default: true). Use together with generate_heatmap_overlayed to control heatmap appearance.
  • model: Model or routing hint (default: generic). Supported examples include generic, sheerid, or instance_id/model (e.g. my-instance-id/generic) to send the job to a dedicated queue for that instance. Invalid instance_id values are rejected with 400.
  • user_agent: Optional string stored with the document for analytics/support.

Example Response

{
    "id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
    "status": "pending"
}

The response includes a unique image ID for tracking the detection status.

Query Detection Status and Results

To check the status and retrieve the results, use the /query endpoint with the image ID.

Authentication: The request body only includes id; the API does not send an API key on this call. Anyone who knows the UUID can poll results—treat document IDs as sensitive if you need to restrict who can see scores.

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

Example Request

curl -X 'POST' \
  'https://detect-image.truthscan.com/query' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "id": "IMAGE-ID-GOES-HERE"
}'

Example Response

{
    "id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
    "status": "done",
    "result": 90.2371538185235,
    "result_details": {
        "is_valid": true,
        "detection_step": 3,
        "final_result": "AI Generated",
        "metadata": [
            "No Information Detected for Real/AI",
            "Could not find anything from ExifTool and Pillow metadata"
        ],
        "metadata_basic_source": "null",
        "ocr": [
            "OCR did not detect AI",
            0.0
        ],
        "ml_model": [
            "AI Generated",
            90.2371538185235
        ],
        "confidence": 90.2371538185235,
        "heatmap_status": "ready",
        "heatmap_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/uploads/....",
        "analysis_results_status": "pending",
        "analysis_results": null,
        "warnings": [
            { "type": "blur_dark", "label": "Blurred" },
            { "type": "watermark", "label": "Gemini", "confidence": 0.95 },
            { "type": "screen_recapture", "label": "screen", "metrics": { "is_screen": false }, "confidence": 99.99 }
        ]
    },
    "preview_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/previews/..."
}

Example Response (/query, secure URLs enabled on the org)

{
    "id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
    "status": "done",
    "result": 90.2371538185235,
    "result_details": {
        "is_valid": true,
        "detection_step": 3,
        "final_result": "AI Generated",
        "confidence": 90.2371538185235,
        "heatmap_status": "ready",
        "heatmap_url": "https://ai-image-detect.undetectable.ai/heatmap/00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
        "analysis_results_status": "ready",
        "analysis_results": null
    },
    "preview_url": "https://ai-image-detect.undetectable.ai/preview/00fee5ff-a55b-42fb-b7c7-d14f05ae0769"
}

Example Response when analysis results are ready

{
    "id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
    "status": "done",
    "result": 90.2371538185235,
    "result_details": {
        "heatmap_status": "ready",
        "heatmap_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/uploads/....",
        "analysis_results_status": "ready",
        "analysis_results": {
            "imageTags": ["person", "portrait", "outdoor", "vineyard", "smiling"],
            "agreement": "strong",
            "confidence": 92,
            "keyIndicators": [
                "Unnaturally smooth skin texture",
                "Consistent lighting anomalies"
            ],
            "detailedReasoning": "The image shows clear signs of AI generation with unnaturally smooth textures and consistent lighting patterns not typical of real photography.",
            "visualPatterns": ["Uniform noise pattern typical of diffusion models"],
            "recommendations": [
                "Cross-reference with original source if available",
                "Check for metadata inconsistencies",
                "Compare with known AI generation patterns"
            ]
        }
    },
    "preview_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/previews/..."
}

Result Details

  • is_valid: Indicates if the image file is valid (true/false).
  • detection_step: Stage at which detection completed: 1 = only metadata; 2 = metadata and ocr; 3 = metadata, ocr, and ml_model.
  • final_result: Overall determination (e.g. "AI Generated", "Real", "Digitally Edited", "AI Edited").
  • confidence: Confidence score of the detection.
  • metadata: Information extracted from image metadata using ExifTool and Pillow.
  • metadata_basic_source: May indicate whether the image was captured with a specific mobile camera model, generated by an AI tool, or modified with photo-editing software.
  • ocr: Watermark-detection result under the historical field name ocr. Two-element array [label, score]: label is a detected watermark class (e.g. "Gemini") or "OCR did not detect AI"; score is on a 0–100 scale (or 0 when unsure). Summarized in warnings when a label is present.
  • ml_model: Results from the machine learning model.
  • warnings: Optional array of heterogeneous warning objects (type blur_dark, watermark, screen_recapture, etc.). May be empty or omitted.
  • preview_url: Preview image URL if generate_preview was true. May be direct storage or, when secure URLs are enabled, an API path such as https://<api-host>/preview/<document_id>.
  • heatmap_status: pending, ready, or failed. Heatmap generation is asynchronous.
  • heatmap_url: Heatmap when heatmap_status is ready. Appearance depends on generate_heatmap_overlayed. May be direct storage or API path https://<api-host>/heatmap/<document_id> (use POST /heatmap/{id} with key when secure).
  • analysis_results_status: pending, ready, skipped, failed, or analyzing. Omitted or null when generate_analysis_details was false.
  • analysis_results: Detailed narrative analysis when enabled; see Analysis Result Explanation below.

Analysis Result Explanation

When analysis_results is ready, it typically includes: agreement (strong | moderate | weak | disagreement), imageTags (up to five short tags), confidence (0–100), keyIndicators, detailedReasoning, visualPatterns, and recommendations.

Notes

  • Heatmap generation is asynchronous. Poll /query for heatmap_status and heatmap_url.
  • Detailed analysis is asynchronous unless generate_analysis_details=false. Poll for analysis_results_status and analysis_results.
  • Secure URLs: When enabled, heatmap_url and preview_url may use the API host; fetch with POST /heatmap/{id} and POST /preview/{id} with your key (see Secure heatmap and preview assets).
  • Poll /query again after the main score is ready to pick up heatmap and analysis_results when they finish.

Heatmap and overlay behavior

The file at heatmap_url reflects generate_heatmap_overlayed and generate_heatmap_normalized from your /detect (or /bulk-upload) request: default overlay (true) is a normal image with the heatmap overlaid; false is typically a PNG with transparency for compositing.

Example: result ~90.24 with final_result AI Generated and detection_step 3 means full pipeline metadata, OCR, and ML model completed.

Analysis Results (Asynchronous Deep Analysis)

When generate_analysis_details is true in /detect, detailed analysis may complete after the main score. Poll /query until analysis_results_status is ready (or skipped/failed).

1. Initial result may be ready before analysis

Core detection (result, final_result, confidence) can be done while analysis_results_status is still pending.

{
    "id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
    "status": "done",
    "result": 90.2371538185235,
    "result_details": {
        "is_valid": true,
        "detection_step": 3,
        "final_result": "AI Generated",
        "confidence": 90.2371538185235,
        "analysis_results_status": "pending",
        "analysis_results": null
    }
}

What to do

Use core fields immediately; keep polling if you need analysis_results.

2. Keep polling

Call /query with the same id until analysis_results_status changes from pending.

curl -X 'POST' \
  'https://detect-image.truthscan.com/query' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769"
}'

3. Analysis complete

When analysis_results_status is ready, analysis_results includes agreement, imageTags, confidence, keyIndicators, detailedReasoning, visualPatterns, and recommendations.

{
    "id": "00fee5ff-a55b-42fb-b7c7-d14f05ae0769",
    "status": "done",
    "result": 90.2371538185235,
    "result_details": {
        "is_valid": true,
        "detection_step": 3,
        "final_result": "AI Generated",
        "confidence": 90.2371538185235,
        "heatmap_status": "ready",
        "heatmap_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/uploads/....",
        "analysis_results_status": "done",
        "analysis_results": {
            "imageTags": [
                "person",
                "portrait",
                "outdoor",
                "vineyard",
                "smiling"
            ],
            "agreement": "strong",
            "confidence": 92,
            "keyIndicators": [
                "Unnaturally smooth skin texture",
                "Consistent lighting anomalies"
            ],
            "detailedReasoning": "The image shows clear signs of AI generation with unnaturally smooth textures and consistent lighting patterns not typical of real photography.",
            "visualPatterns": [
                "Uniform noise pattern typical of diffusion models"
            ],
            "recommendations": [
                "Cross-reference with original source if available",
                "Check for metadata inconsistencies",
                "Compare with known AI generation patterns"
            ]
        }
    },
    "preview_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/previews/..."
}

When analysis is not available

If analysis_results_status is skipped, failed, or absent, or generate_analysis_details was false, treat core detection as final.

{
    "status": "done",
    "result": 12.5,
    "result_details": {
        "analysis_results_status": "skipped",
        "analysis_results": null
    }
}

Analysis Results Fields

  • analysis_results_status: pending | ready | skipped | failed | analyzing
  • analysis_results.agreement: strong | moderate | weak | disagreement
  • analysis_results.imageTags: short descriptive tags
  • analysis_results.confidence: 0–100
  • analysis_results.keyIndicators: specific cues
  • analysis_results.detailedReasoning: short explanation
  • analysis_results.visualPatterns: broader patterns
  • analysis_results.recommendations: next steps

Bulk Upload (ZIP)

Submit multiple images in one request by uploading a ZIP. Workflow mirrors single-image: presign (ZIP name) → PUT ZIP → POST /bulk-upload → poll /query.

1. Obtain a Pre-signed Upload URL (ZIP)

Use get-presigned-url with a .zip filename (e.g. images.zip).

GET https://detect-image.truthscan.com/get-presigned-url?file_name=images.zip

Example Request

curl -X GET 'https://detect-image.truthscan.com/get-presigned-url?file_name=images.zip' \
--header 'apikey: YOUR API KEY GOES HERE'

2. Upload the ZIP

PUT the ZIP to the presigned URL with Content-Type: application/zip.

curl -X PUT '<PRESIGNED_URL_FOR_images.zip>' \
  --header 'Content-Type: application/zip' \
  --header 'x-amz-acl: private' \
  --data-binary '@images.zip'

ZIP Limits

  • Maximum ZIP size: 100MB
  • Maximum images per bulk: 50
  • Per-image limits: minimum 1KB, maximum 10MB

Supported formats inside ZIP

JPG, JPEG, PNG, WebP, JFIF, HEIC, HEIF, AVIF, BMP, TIFF, TIF, GIF, SVG

PDF files inside the ZIP are not supported and will be skipped.

SVG files are converted to PNG before detection.

3. Submit ZIP for Bulk Detection

POST /bulk-upload with key and url pointing to the uploaded ZIP path.

Optional Parameters

  • generate_preview: Set to true to generate preview URLs for images (default: false).
  • generate_analysis_details: Set to true to generate detailed analysis (default: false).
  • generate_heatmap_overlayed: Same behavior as /detect (overlay vs transparent RGBA heatmap).
  • generate_heatmap_normalized: Same behavior as /detect (default: true).
  • model: Model domain: generic, sheerid, or instance_id/model format.

Example Request

curl -X 'POST' \
  'https://detect-image.truthscan.com/bulk-upload' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "key": "YOUR-API-KEY-GOES-HERE",
  "url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/<FILE_PATH>",
  "generate_preview": false,
  "generate_analysis_details": false,
  "model": "generic"
}'

Example Response

{
    "id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
    "status": "pending",
    "expected_count": 12
}

Returns id, status pending, and expected_count (how many images from the ZIP will be analyzed).

How bulk ZIP results update

  • After submit, status is pending until processing begins, then analyzing.
  • results lists each image; pending entries have result and result_details null until done.
  • Optional heatmaps and analysis details may still be pending inside result_details until ready.
  • When every image in results has finished, overall status becomes done. If the batch cannot complete, status may be failed.
  • You can call /query before the ZIP finishes to see partial results.

4. Query Bulk Upload Results

Use POST /query with the id from /bulk-upload. Same endpoint as single-image; response shape depends on whether the id is a single image or a ZIP batch.

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

Example Response (still processing)

{
  "id": "3b81fb24-dd23-40e7-ae95-82f823f44098",
  "status": "analyzing",
  "results": [
    {
      "id": "4600c7e5-00ec-469d-9117-ff20e0f1c1fa",
      "status": "done",
      "result": 44.0006,
      "result_details": {},
      "filename": "photo1.jpg",
      "preview_url": null
    },
    {
      "id": "2f770c89-352a-4d53-b6a3-a2147ca2c0ae",
      "status": "pending",
      "result": null,
      "result_details": null,
      "filename": "photo2.jpg",
      "preview_url": null
    }
  ],
  "skipped": []
}

Response fields (bulk ZIP)

  • id — Bulk request id.
  • status — pending, then analyzing, then done or failed.
  • results — One entry per image being analyzed (id, status, result, result_details, filename, preview_url when available).
  • skipped — Files not analyzed (unsupported type, size, etc.) with status failed and reason in result_details.

Billing: Credits are used only for images successfully analyzed. Failed SVG conversions and skipped files are not billed.

Secure heatmap and preview assets

When heatmap_url or preview_url in /query point to API host (not direct object storage), download the bytes with POST and your key.

POST /heatmap/{id}

POST /preview/{id}

Request body JSON: { "key": "YOUR-API-KEY-GOES-HERE" }

Heatmap responses (check HTTP status and Content-Type)

  • 200 + binary (image/png, etc.) — Heatmap file available. X-Heatmap-Status may be set.
  • 202 + JSON — heatmap_status pending; poll /query and retry.
  • 200 + JSON — No heatmap to serve (optional feature, failed, etc.); not a server error.
  • 500 + JSON — Stored heatmap_url exists but file could not be downloaded from storage; retry later.
  • 404 + JSON — Document id not found.
  • 403 + JSON — API key does not own this document.

Preview: POST /preview/{id} returns raw preview bytes. 404 with JSON if no preview was generated (generate_preview was false).

Examples

curl -X POST 'https://detect-image.truthscan.com/heatmap/00fee5ff-a55b-42fb-b7c7-d14f05ae0769' \
  -H 'Content-Type: application/json' \
  -d '{"key":"YOUR-API-KEY-GOES-HERE"}' \
  --output heatmap.png
curl -X POST 'https://detect-image.truthscan.com/preview/00fee5ff-a55b-42fb-b7c7-d14f05ae0769' \
  -H 'Content-Type: application/json' \
  -d '{"key":"YOUR-API-KEY-GOES-HERE"}' \
  --output preview.png

Internal: organization usage sync to Stripe (job secret)

Trusted backend jobs only, not general API customers. Requires header x-job-secret matching server JOB_SECRET. Syncs metered TruthScan organization usage to Stripe for a date range.

POST /organizations/{org_id}/usage/sync-to-stripe

Headers: x-job-secret: <JOB_SECRET>

Body JSON: start_date, end_date, optional idempotency_id for Stripe meter idempotency.

Returns success, organization_id, total_documents, value_sent_to_stripe, report_date, message. 400 if org not metered or missing stripe_customer_id when needed; 401 invalid secret; 404 org not found; 500 Stripe/config errors.

Check User Credits

This endpoint accepts the user's apikey via the header and returns credit details.

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

Example Request

curl -X 'GET' \
  'https://detect-image.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
}

For external integrations, only the credits field will be populated.

Health Check

Check the health status of the API server.

GET https://detect-image.truthscan.com/health

Example Request

curl -X 'GET' \
  'https://detect-image.truthscan.com/health' \
  -H 'accept: application/json'

Example Response

{
    "status": "healthy"
}

A "healthy" response indicates the service is operating normally.

Errors

Most errors will be from incorrect parameters being sent to the API. Double-check each call and try the provided examples.

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

Error CodeMeaning
400Bad Request -- Your request is invalid.
401Unauthorized -- Invalid job secret (internal usage endpoints) or similar auth failure.
403Forbidden -- The API key is invalid, access denied, or there aren't sufficient credits for the operation.
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, 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 image processing

Solution:

  1. Check your remaining credits using /check-user-credits
  2. Purchase additional credits if needed

Input Validation Issues

"Input URL cannot be empty" (400)

Cause: Empty or invalid URL submitted

Solution:

  1. Ensure your url input is not empty
  2. Remove leading/trailing whitespace in image names
  3. Check URL 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

"Unsupported image type" (400)

Cause: File format not supported

Solution:

  1. Convert to a supported format (JPG, PNG, WebP, HEIC, HEIF, AVIF, BMP, TIFF, GIF, SVG, PDF)
  2. Check file extension is correct

"File size is too small" (400)

Cause: Image file is below minimum size requirement

Solution:

  1. Use a larger image file (minimum 1KB)
  2. Check if the image was corrupted during upload

"File size exceeds limit" (400)

Cause: Image file is too large

Solution:

  1. Compress or resize the image; the maximum size is set per deployment (the API error message states the limit in MB)
  2. Use a different image format

"Invalid file type" (400)

Cause: File type validation failed

Solution:

  1. Ensure the file is a valid image format
  2. Check the file is not corrupted
  3. Verify MIME type matches file extension

Processing Issues

Image status "failed"

Cause: Processing failed for various reasons

Solution:

  1. Verify URL is in a supported format
  2. Check the image file is valid and not corrupted
  3. Ensure the image meets size requirements
  4. Contact support if the issue persists

"User not found"

Cause: Invalid user ID

Solution:

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

"File metadata could not be fetched" (500)

Cause: Unable to access uploaded file

Solution:

  1. Verify file was uploaded successfully
  2. Check file URL is accessible
  3. Try re-uploading the file

Upload Issues

"Image upload failed" (403/400)

Cause: Invalid or expired pre-signed URL, or issues with the storage server

Solution:

  1. Use the pre-signed URL promptly after receiving it
  2. Verify Content-Type matches the file format
  3. Remove spaces from the filename before upload
  4. Generate a new pre-signed URL if needed

"Invalid pre-signed URL" (400)

Cause: Filename with spaces or expired/corrupted pre-signed URL

Solution:

  1. Remove spaces from the filename before requesting a pre-signed URL
  2. Use alphanumeric characters, hyphens, and underscores
  3. Generate a new pre-signed URL if needed

Bulk Upload Issues

"URL must point to a ZIP file" (400)

Cause: The URL provided to /bulk-upload does not point to a ZIP file

Solution:

  1. Use get-presigned-url?file_name=images.zip (or another .zip filename)
  2. Upload a valid ZIP to the presigned URL
  3. Ensure the bulk-upload request url points to that uploaded ZIP

"ZIP file too large" (400)

Cause: ZIP exceeds maximum size (100MB)

Solution:

  1. Reduce the number of images or compress them
  2. Split into multiple bulk uploads

"Too many files" (400)

Cause: ZIP contains more than 50 valid images

Solution:

  1. Reduce to 50 or fewer images per ZIP
  2. Split into multiple bulk uploads

"No valid images found in ZIP" (400)

Cause: All files in the ZIP were skipped (unsupported format, too small, invalid path, etc.)

Solution:

  1. Use supported formats (JPG, PNG, WebP, HEIC, HEIF, AVIF, BMP, TIFF, TIF, GIF, SVG)
  2. PDF is not supported in bulk
  3. Each image must be at least 1KB and at most 10MB
  4. Avoid hidden files (names starting with .) and path traversal (..)

"Document is not a bulk upload (image-zip) result" (400)

Cause: The id does not match that upload type (single image vs ZIP batch)

Solution:

  1. Use the id from /detect for single-image submissions
  2. Use the id from /bulk-upload for ZIP submissions

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 image detection API.