# AI Image Detector

> Detect whether an image is AI-generated or partially AI-generated.

<RequestExample>

```bash title="cURL" icon="terminal"
curl --request POST \
  --url https://api.copyleaks.com/v1/ai-image-detector/my-scan-123/check \
  --header 'Authorization: Bearer YOUR_LOGIN_TOKEN' \
  --form 'image=@/path/to/test-image.png' \
  --form 'filename=test-image.png' \
  --form 'sandbox=true' \
  --form 'model=ai-image-1-ultra' \
  --form 'maskType=heatmap' \
  --form 'objectDetection=[{"object":"face"},{"object":"hand"}]'
```

```python title="Python" icon="python"
import base64
from copyleaks.copyleaks import Copyleaks
from copyleaks.clients.image_detection_client import ImageDetectionClient
from copyleaks.models.ai_image_detection import (
    CopyleaksAiImageDetectionRequestModel,
    CopyleaksAiImageDetectionModels,
)

auth_token = Copyleaks.login("your@email.address", "YOUR_API_KEY")

with open("test-image.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode("utf-8")

payload = CopyleaksAiImageDetectionRequestModel(
    base64=b64,
    filename="test-image.png",
    model=CopyleaksAiImageDetectionModels.AI_IMAGE_1_ULTRA,
    sandbox=True,
)

client = ImageDetectionClient()
response = client.submit(auth_token, "my-scan-123", payload)
print(response)
```

```javascript title="JavaScript" icon="square-js"
const imageFile = document.getElementById('fileInput').files[0];
const formData = new FormData();

formData.append('image', imageFile);
formData.append('filename', imageFile.name);
formData.append('sandbox', 'true');
formData.append('model', 'ai-image-1-ultra');
formData.append('maskType', 'heatmap');
// Optional: objects to locate, sent as a JSON-encoded string in one form field
formData.append('objectDetection', JSON.stringify([{ object: 'face' }, { object: 'hand' }]));

const response = await fetch(
  'https://api.copyleaks.com/v1/ai-image-detector/my-scan-123/check',
  {
    method: 'POST',
    headers: { 'Authorization': 'Bearer YOUR_LOGIN_TOKEN' },
    body: formData,
  }
);
const result = await response.json();
```

</RequestExample>

<ResponseExample>

```json 200 OK
{
  "model": "ai-image-1-ultra",
  "result": {
    "starts": [0, 512, 1536, 2560],
    "lengths": [256, 512, 768, 1024]
  },
  "summary": { "human": 0.3, "ai": 0.7 },
  "isAiDetected": true,
  "imageInfo": {
    "shape": { "height": 1024, "width": 768 },
    "metadata": {
      "issuedTime": "2025-07-23T12:44:05",
      "issuedBy": "OpenAI",
      "appOrDeviceUsed": "OpenAI-API",
      "contentSummary": "Created using generative AI"
    }
  },
  "detectedObjects": [
    {
      "object": "face",
      "mask": { "starts": [1024, 3072], "lengths": [512, 256] }
    },
    {
      "object": "hand",
      "mask": { "starts": [8192], "lengths": [128] }
    }
  ],
  "scannedDocument": {
    "scanId": "my-scan-123",
    "actualCredits": 1,
    "expectedCredits": 1,
    "creationTime": "2023-01-10T10:07:58.9459512Z"
  }
}
```

</ResponseExample>

Detect whether an image is AI-generated or partially AI-generated. Returns a detailed analysis with an RLE mask indicating AI-generated regions. Optionally, pass `objectDetection` to also locate specific objects in the image (for example a face or a hand) and receive a segmentation mask for each one in the same response.

<Note>
  AI Image Detection has wrapper support in the **Python SDK** via `ImageDetectionClient`. The JavaScript and Java SDKs don't yet expose a method for this endpoint, so those samples call the HTTP API directly.
</Note>

<Warning>
**Authentication Required.** You need to login with a user and API key in order to access this method. Add this HTTP header to your request:

**Authorization: Bearer &lt;Your-Login-Token&gt;**
</Warning>

<Warning title="Rate Limits">
Image detection API has a rate limit of **900 requests per 15 minutes** per host. If exceeded, requests will be rejected with a 429 status code until the rate limit window resets.
</Warning>

## Request

### Path Parameters

<ParamField path="scanId" type="string" required>
  A unique scan id provided by you. We recommend you use the same id in your database to represent the scan in the Copyleaks database. This will help you to debug incidents. Using the same ID for the same file will help you to avoid network problems that may lead to multiple scans for the same file. Learn more about [the criteria for creating a Scan ID](/concepts/management/choosing-scan-id).

  `>= 3 characters` `<= 36 characters`
</ParamField>

### Supported Content Types

Submit images using **multipart/form-data** (recommended) or **JSON with base64**.

<Tip title="Performance Tip">
`multipart/form-data` sends the image file directly without base64 encoding overhead, making it more efficient for large images. Use `application/json` when you need to submit image data as a base64-encoded string.
</Tip>

#### Option 1: Multipart/Form-Data (Recommended)

**Headers:**
```http
Content-Type: multipart/form-data
Authorization: Bearer YOUR_LOGIN_TOKEN
```

#### Option 2: JSON with Base64

**Headers:**
```http
Content-Type: application/json
Authorization: Bearer YOUR_LOGIN_TOKEN
```

<Tip title="Performance Tip">
The `Accept-Encoding: gzip` header enables response compression, reducing bandwidth usage and improving performance.
</Tip>

### Body Parameters

The image field used depends on the content type:
- **`multipart/form-data`** -> use the `image` field (binary file)
- **`application/json`** -> use the `base64` field (base64-encoded string)

<ParamField body="image" type="file">
  Binary image file. Required when using `multipart/form-data`. Base64-encoded images are not accepted for multipart requests.

  **Requirements:**
  - **Size:** Minimum 512x512px, maximum 6000x4500px (27 megapixels)
  - **File size:** Less than 32MB
  - **Formats:** PNG, JPG, JPEG, BMP, WebP, HEIC/HEIF
</ParamField>
<ParamField body="base64" type="string">
  Base64-encoded image data. Required when using `application/json` content type.

  **Requirements:**
  - **Size:** Minimum 512x512px, maximum 6000x4500px (27 megapixels)
  - **File size:** Less than 32MB (before encoding)
  - **Formats:** PNG, JPG, JPEG, BMP, WebP, HEIC/HEIF
</ParamField>
<ParamField body="filename" type="string" required>
  The name of the image file including its extension.

  **Requirements:**
  - Allowed file extensions: `.png`, `.jpg`, `.jpeg`, `.bmp`, `.webp`, `.heic`, `.heif`
  - `<= 255 characters`
</ParamField>
<ParamField body="model" type="string" required>
  The AI detection model to use for analysis.

  - AI Image 1 Ultra: `"ai-image-1-ultra"`
</ParamField>
<ParamField body="maskType" type="string" default="binary">
  The type of detection mask to return alongside the detection result. Use `"heatmap"` when you want a pixel-level visualization of how confidently each region of the image was flagged as AI-generated, or `"none"` when you only need the scores.

  Supported values:
  - `"binary"` (default) - Run-Length Encoded (RLE) mask of the regions flagged as AI-generated, returned as `result.starts` and `result.lengths`.
  - `"heatmap"` - gradient overlay highlighting AI-generated regions with intensity proportional to confidence. Adds a `labels` array to `result` with one confidence band (`0`-`4`) per RLE run.
  - `"none"` - no mask. The response omits the `result` object; every other field is unchanged.

  Any other value is rejected with `400 Bad Request`.

  Example: `"heatmap"`
</ParamField>
<ParamField body="objectDetection" type="array">
  Optional. A list of objects to locate and segment within the image. When provided, the response additionally includes a `detectedObjects` array - one entry per object found in the image, each with its Run-Length Encoded (RLE) segmentation mask. Objects that were requested but not found are omitted, so look entries up by `object` rather than by position.

  Each entry wraps the object name in an object (`{ "object": "face" }`) so future per-entry fields can be added without a breaking change.

  - Maximum 3 entries.
  - Each entry's `object` value must be a non-empty string of at most 32 characters.
  - Using `objectDetection` does not change the cost of the request.

  **`multipart/form-data`:** send the list as a JSON-encoded string in a single form field, for example `objectDetection=[{"object":"face"},{"object":"hand"}]`.

  **`application/json`:** send the list as a JSON array.

  Example: `[{ "object": "face" }, { "object": "hand" }]`
</ParamField>
<ParamField body="sandbox" type="boolean" default="false">
  Use sandbox mode to test your integration with the Copyleaks API without consuming any credits.
</ParamField>

## Responses

<Tabs>
  <Tab title="200">
    <Check>**200 OK** - The image was successfully analyzed.</Check>

    ```json
    {
      "model": "ai-image-1-ultra",
      "result": {
        "starts": [0, 512, 1536, 2560],
        "lengths": [256, 512, 768, 1024]
      },
      "summary": { "human": 0.3, "ai": 0.7 },
      "isAiDetected": true,
      "detectedObjects": [
        { "object": "face", "mask": { "starts": [1024, 3072], "lengths": [512, 256] } }
      ]
    }
    ```

    When the request includes `maskType: "heatmap"`, `result` additionally carries a `labels` array - one confidence band (`0`-`4`) per RLE run. With `maskType: "none"` the `result` object is omitted altogether. `detectedObjects` is present only when the request included `objectDetection`. See the [AI Image Detection Response](/reference/data-types/ai-detector/ai-image-detection-response) reference.
  </Tab>
  <Tab title="400">
    <Warning>**400 Bad Request** - Invalid request parameters, unsupported image format, or image processing issues.</Warning>
  </Tab>
  <Tab title="401">
    <Warning>**401 Unauthorized** - Authentication or authorization issues.</Warning>
  </Tab>
  <Tab title="402">
    <Warning>**402 Payment Required** - Insufficient credits.</Warning>
  </Tab>
  <Tab title="429">
    <Warning>**429 Too Many Requests** - Too many requests have been sent. The request has been rejected.</Warning>
  </Tab>
  <Tab title="500">
    <Warning>**500 Internal Server Error** - The server encountered an internal error or misconfiguration.</Warning>
  </Tab>
</Tabs>
