Articles on: Developer API

Image 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-image-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


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


Note: It is necessary to remove spaces from the image filename when requesting a pre-signed URL.

PDF note: For PDF files, only the first image will be detected.


**GET ** https://ai-image-detect.undetectable.ai/get-presigned-url?file_name=example.jpg


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


Example Request


curl -X GET 'https://ai-image-detect.undetectable.ai/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 (see below).


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.


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' # Attachment


Set the Content-Type header 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
# PNG example
curl -X PUT '<PRESIGNED_URL_FOR_example.png>' \
--header 'Content-Type: image/png' \
--header 'x-amz-acl: private' \
--data-binary '@example.png'

# PDF example
curl -X PUT '<PRESIGNED_URL_FOR_example.pdf>' \
--header 'Content-Type: application/pdf' \
--header 'x-amz-acl: private' \
--data-binary '@example.pdf'

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

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.

Note: It is necessary to remove spaces from the image filename when uploading the image.


Ensure that the file format remains consistent during the upload process. A successful upload will return a status code of 200.


File Size Limits:

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


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://ai-image-detect.undetectable.ai/detect


Example Request


curl -X 'POST' \
'https://ai-image-detect.undetectable.ai/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 obtained from the response in the initial step, "Obtain a Pre-signed Upload URL".


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 over the original or another UI in your app.
  • 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.


Bulk Upload (ZIP)


Submit multiple images for AI detection in a single request by uploading a ZIP file. The workflow mirrors the single-image flow:


  • Obtain a Pre-signed Upload URL (for the ZIP file)
  • Upload the ZIP
  • Submit the ZIP for Bulk Detection
  • Check the status and results with /query


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


Request a pre-signed URL for your ZIP file. Use the same get-presigned-url endpoint with a .zip filename.


**GET ** https://ai-image-detect.undetectable.ai/get-presigned-url?file_name=images.zip


Example Request


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


2. Upload the ZIP


Use the provided presigned_url to upload your ZIP via a PUT request.


Example Request


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


Note: 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 ** https://ai-image-detect.undetectable.ai/bulk-upload


Example Request


curl -X 'POST' \
'https://ai-image-detect.undetectable.ai/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"
}'


The FILE_PATH refers to the path from the presigned URL response (e.g., uploads/images.zip).


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 results (default: false)
  • generate_heatmap_overlayed: Same behavior as for /detect: true (default) = heatmap blended on the original image; false = transparent RGBA heatmap only for custom compositing.
  • model: Model domain - generic, sheerid, or instance_id/model format


Example Response


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


The response includes a unique ID for tracking the bulk request, an initial status of pending, and expected_count (how many images from the ZIP will be analyzed).


How bulk ZIP results update


When you check /query while a ZIP is still processing, you can see progress for each image as it is analyzed.


  • After you submit the ZIP, status is pending until processing begins, then it becomes analyzing.
  • The results array lists each image. Entries that are not finished yet show status: pending with result and result_details set to null. As each image finishes, that entry updates with its score and details. Files that could not be analyzed appear under skipped with a failed status and an explanation in result_details.
  • Optional heatmaps and analysis details for a given image may still show as pending inside result_details until they are ready-the same behavior as for single-image detection (see Query Detection Status and Results below).
  • When every image in results has finished, the overall status becomes done. If the bulk request cannot be completed, status may be failed.


You can call /query again on the same ID to refresh the response; you do not need to wait until the whole ZIP is finished before you see individual image results.


4. Query Bulk Upload Results


To check the status and retrieve results for a bulk ZIP, use the /query endpoint with the id returned from /bulk-upload. This is the same endpoint as for single-image detection; the JSON you get back depends on whether the id belongs to a single image or a ZIP batch.


Keep checking until status is done or failed, or use the partial results while status is still pending or analyzing if you want to show live progress.


**POST ** https://ai-image-detect.undetectable.ai/query


Example Request


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


Example Response (still processing)


While status is analyzing, some images in results may already be done while others are still pending:


{
"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": []
}


Tip: To estimate how far along the batch is, compare the number of images whose status is done or failed to the total number of entries in results.


Example Response (complete)


When status is done, each image in results has a final status (done or failed). The fields inside result_details for each image follow the same structure as in the single-image /query response (for example final_result, confidence, metadata, ocr, ml_model, heatmap fields, and optional analysis fields where enabled).


{
"id": "77565038-9e3d-4e6a-8c80-e20785be5ee9",
"status": "done",
"results": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "done",
"result": 90.23,
"filename": "image1.jpg",
"preview_url": "https://ai-image-detector-prod.nyc3.digitaloceanspaces.com/previews/...",
"result_details": {
"is_valid": true,
"detection_step": 3,
"final_result": "AI Generated",
"confidence": 90.23,
"metadata": ["..."],
"ocr": ["OCR did not detect AI", 0.0],
"ml_model": ["AI Generated", 90.23],
"heatmap_status": "ready",
"heatmap_url": "https://...",
"analysis_results_status": "ready",
"analysis_results": null
}
}
],
"skipped": [
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"status": "failed",
"result": null,
"filename": "document.pdf",
"result_details": {
"is_valid": false,
"error_message": "PDF not supported in bulk"
}
}
]
}


Response fields (bulk ZIP):


  • id - The ID for this bulk ZIP request.
  • status - Overall progress: pending, then analyzing, then done when all images are finished, or failed if the request could not be completed.
  • results - One entry per image from the ZIP that is being analyzed. Each entry includes id, status, result, result_details, and when available filename and preview_url. Until that image has finished, status is pending and result / result_details are null.
  • skipped - Files that were not analyzed (for example unsupported type, invalid path, or size limits). Each entry uses the same shape; status is usually failed with the reason in result_details.


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



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://ai-image-detect.undetectable.ai/query


Example Request


curl -X 'POST' \
'https://ai-image-detect.undetectable.ai/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
},
"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"
}


Notes:


  1. Heatmap generation is asynchronous. Initially, heatmap_status will be pending and heatmap_url may be absent or null. When ready, heatmap_status becomes ready and heatmap_url is populated. The file at heatmap_url reflects generate_heatmap_overlayed from your /detect (or /bulk-upload) request: with the default (true) it is a normal image with the heatmap overlaid on the photo; with false it is typically a PNG with transparency showing only the colored activation map so you can layer it yourself.


  1. Detailed analysis (unless turned off with generate_analysis_details=false) is asynchronous. Initially, analysis_results_status will be pending and analysis_results may be absent or null. When ready, analysis_results_status becomes ready (or skipped / failed in edge cases) and analysis_results is populated.


  1. Secure URLs: When enabled, heatmap_url and preview_url in /query may use this API’s host (see Example Response (/query, secure URLs enabled on the org) above). Fetch with POST /heatmap/{id} and POST /preview/{id} and your key — see Secure heatmap and preview assets below.


Tip: Poll /query again after the main score is ready to pick up heatmap and analysis_results when they finish.


Example Response when analysis results are ready


{
"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": "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: Indicates the stage at which detection was completed.
  • 1: Only metadata is returned.
  • 2: Returns metadata and ocr results.
  • 3: Returns metadata, ocr, and ml_model results.
  • final_result: The overall determination (e.g., "AI Generated", "Real", "Digitally Edited, "AI Edited").
  • confidence: The confidence score of the detection.
  • metadata: Information extracted from image metadata using ExifTool and Pillow.
  • metadata_basic_source: This information may indicate whether the image was captured using a specific mobile camera model, generated by an AI tool, or modified using photo-editing software.
  • ocr: Results from Optical Character Recognition analysis for watermark detection.
  • ml_model: Results from the machine learning model.
  • preview_url: URL to the preview image (if generate_preview was set to true). May be a direct object-storage URL or, when secure URLs are enabled, an API path such as https://<api-host>/preview/<document_id>.
  • heatmap_status: Status of heatmap generation (pending, ready, or failed).
  • heatmap_url: URL to the heatmap image, available when heatmap_status is ready. Appearance depends on generate_heatmap_overlayed at submit time: overlaid on the original (default), or transparent heatmap-only when set to false. May be a direct object-storage URL or, when secure URLs are enabled, an API path such as https://<api-host>/heatmap/<document_id> (use POST /heatmap/{id} — see below).
  • analysis_results_status: Status of detailed analysis (pending, ready, skipped, failed, or analyzing while work is in progress). Omitted or null when generate_analysis_details was not requested or was false on /detect / /bulk-upload.
  • analysis_results: Detailed narrative analysis when enabled; structure below.


Analysis Result Explanation

The analysis_results_status field may include:

  • pending — Queued or not started
  • analyzing — In progress
  • readyanalysis_results is populated
  • skipped / failed — Analysis was not produced (e.g., disabled, error, or unsupported case)


When not ready, analysis_results is null. When ready, it typically includes:


  1. agreement: string — one of strong | moderate | weak | disagreement
  2. imageTags: string[] — up to five short tags describing the image
  3. confidence: number — 0–100
  4. keyIndicators: string[] — specific visual or technical cues that support the assessment
  5. detailedReasoning: string — short explanation tied to the detector outcome
  6. visualPatterns: string[] — broader compositional or artifact patterns
  7. recommendations: string[] — practical next steps for verification



Secure heatmap and preview assets


When heatmap_url or preview_url in /query point to this API host (not directly to object storage), download the image with a POST and the same API key you use for detection.


**POST ** https://ai-image-detect.undetectable.ai/heatmap/{id}


Request body (JSON):


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


Responses (check the HTTP status code and Content-Type):


Status

Body

When

200

Binary (image/png, etc.)

Heatmap file is available. Header X-Heatmap-Status is set when present on the document (e.g. ready).

202

JSON

Heatmap is still generating (heatmap_status is pending and there is no stored heatmap_url yet). Example: {"heatmap_status":"pending","message":"Heatmap is still being generated. Try again shortly."} — call /query again, then retry this endpoint.

200

JSON

No heatmap to serve (optional feature, no URL after processing, or heatmap_status failed). Includes heatmap_status and message — this is not a server error.

500

JSON

A stored heatmap_url exists but the file could not be downloaded from storage — retry later.

404

JSON

Document id not found.

403

JSON

API key does not own this document (Access denied).


The server only downloads from storage when a heatmap_url is present on the document. Pending or absent heatmaps return 202 or 200 JSON — not 500.


**POST ** https://ai-image-detect.undetectable.ai/preview/{id}


Request body (JSON):


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


Response: Raw preview image bytes. Returns 404 with a JSON error if no preview was generated (generate_preview was false).


Examples (heatmap and preview)


Use the same document id from /query in both URLs. The key must match the document owner; otherwise the API returns 403.


HeatmapPOST /heatmap/{id}


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


PreviewPOST /preview/{id}


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



Check User Credits


This endpoint accepts the users apikey via the header. And returns users credit details.


**GET ** https://ai-image-detect.undetectable.ai/check-user-credits


Example Request


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


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



Health Check


Check the health status of the API server.


**GET ** https://ai-image-detect.undetectable.ai/health


Example Request


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


Example Response


{
"status": "healthy"
}



Internal: organization usage (job secret)


These endpoints are for trusted backend jobs, not general API customers. They require header x-job-secret matching the server JOB_SECRET. They are used to report TruthScan organization usage and (optionally) sync metered usage to Stripe.


**POST ** https://ai-image-detect.undetectable.ai/organizations/{org_id}/usage


Headers: x-job-secret: <JOB_SECRET>

Body (JSON):


{
"start_date": "2026-04-01",
"end_date": "2026-04-07"
}


Response (200): organization_id, start_date, end_date, total_documents (completed AI Image Detector documents in range for that org), service_type (ai_image_detector).

Errors: 401 invalid secret, 404 organization not found, 400 if start_date is not before end_date, 500 if JOB_SECRET is not configured.


**POST ** https://ai-image-detect.undetectable.ai/organizations/{org_id}/usage/sync-to-stripe


Headers: x-job-secret: <JOB_SECRET>

Body (JSON):


{
"start_date": "2026-04-01",
"end_date": "2026-04-07",
"idempotency_id": "optional-custom-stripe-meter-idempotency-key"
}


Aggregates the same document counts and sends a Stripe billing meter event for organizations on metered billing with a linked metered product. Response includes success, total_documents, value_sent_to_stripe, report_date, and message. Returns 400 if the organization is not on metered billing or lacks stripe_customer_id when sending usage.



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 Code

Meaning

400

Bad Request -- Your request is invalid.

401

Unauthorized -- Invalid job secret (internal usage endpoints) or similar auth failure.

403

Forbidden -- The API key is invalid, access denied, or there aren't sufficient credits for the operation.

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:


  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 any leading/trailing whitespace in image names
  3. Check if 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 image to 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 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 file is a valid image format
  2. Check 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 image file is valid and not corrupted
  3. Ensure image meets size requirements
  4. Contact support if 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


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 file to the presigned URL
  3. Ensure the URL in the bulk-upload request points to the 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. Ensure images 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 in your request does not go with that upload type (single image vs. ZIP batch).
  • Solution:


  1. Use the id from /detect when you submitted a single image.
  2. Use the id from /bulk-upload when you submitted a ZIP file.



Updated on: 07/04/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!