# IsThisImage Developer API v1

Updated: 2026-10-30. Base URL: https://isthisimageai.org

Buy Developer once ($14.99, 1,500 permanent credits) to unlock lifetime API access.
Starter ($1.99, 50) and Standard ($4.99, 250) also refill the same wallet after unlock.
One successful API check costs one paid credit; the website's daily free check does not apply.
Any confirmed Developer refund revokes access from that purchase, unless another eligible purchase remains.
Create a key at /account/api. Keys are shown once. Keep them server-side and revoke exposed keys.

## POST /api/v1/detect
Bearer authentication. Required Idempotency-Key: UUID v4. multipart/form-data with one image.
JPEG/PNG/WebP, up to 10 MiB and 40 megapixels. Let the client set the multipart boundary.
No image URLs, batch requests, videos or callbacks. Images are not stored as a customer library.
Scores are estimates, not proof of authenticity. Results expose score (0..1) and verdict only.

### curl

```curl
curl 'https://isthisimageai.org/api/v1/detect' \
  -H "Authorization: Bearer $ISTHISIMAGE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F 'image=@photo.jpg'
```

### python

```python
import os, uuid, requests

with open("photo.jpg", "rb") as image:
    response = requests.post(
        "https://isthisimageai.org/api/v1/detect",
        headers={"Authorization": "Bearer " + os.environ["ISTHISIMAGE_API_KEY"],
                 "Idempotency-Key": str(uuid.uuid4())},
        files={"image": ("photo.jpg", image, "image/jpeg")}, timeout=120)
print(response.status_code, response.json())
```

### node

```node
import { readFile } from 'node:fs/promises';

const form = new FormData();
form.set('image', new Blob([await readFile('photo.jpg')], { type: 'image/jpeg' }), 'photo.jpg');
const response = await fetch('https://isthisimageai.org/api/v1/detect', {
  method: 'POST',
  headers: { Authorization: 'Bearer ' + process.env.ISTHISIMAGE_API_KEY,
             'Idempotency-Key': crypto.randomUUID() },
  body: form
});
console.log(response.status, await response.json());
```

## Retries and limits
10 detection POSTs/minute, 60 usage GETs/minute, 2 concurrent checks per account.
Retry uncertain outcomes with the same key and identical bytes. Success replays never charge again,
including at zero balance. credits_charged=1 is the original charge; remaining_credits is current.
Processing returns 409 REQUEST_IN_PROGRESS. A changed image returns 409 IDEMPOTENCY_CONFLICT.
After a terminal failure, start a new check with a new UUID. Failed checks restore credits;
interrupted requests are recovered after 30 minutes by hourly maintenance.
Never switch to a new key merely because a response was lost.

## GET /api/v1/usage
Bearer authentication; returns api_access, credits_remaining, credits_never_expire,
checks_per_credit and api_uses_total. Zero balance returns 200; lost entitlement returns 403.

## Errors
JSON: {"ok":false,"code":"INVALID_API_KEY","request_id":"uuid"}
- 400 INVALID_REQUEST / INVALID_IMAGE: Check the UUID v4, multipart image and image bytes.
- 401 INVALID_API_KEY: Supply an active Bearer key.
- 402 INSUFFICIENT_CREDITS: Buy any credit pack. API access remains unlocked.
- 403 API_ACCESS_REQUIRED: An unrefunded Developer purchase is required.
- 409 IDEMPOTENCY_CONFLICT: Key belongs to another image, source, user, or a failed request.
- 409 REQUEST_IN_PROGRESS: Retry with the same key and image after a delay.
- 409 CONCURRENCY_LIMIT: At most two active checks per account.
- 413 IMAGE_TOO_LARGE: Maximum image size is 10 MiB.
- 415 UNSUPPORTED_IMAGE: Use JPEG, PNG or WebP.
- 429 RATE_LIMITED: Respect Retry-After.
- 503 API_UNAVAILABLE / DETECTOR_UNAVAILABLE: Temporarily unavailable.
- 504 PROVIDER_TIMEOUT: Check timed out. Failed paid checks are restored.
- 500 INTERNAL_ERROR: Retry the same key to resolve an uncertain outcome.

OpenAPI: https://isthisimageai.org/openapi.json
