AI Image Detection API for Developers

Send an image or video, get a structured forensic verdict with a confidence score and per-signal evidence. One bearer token, one POST, no application form.

curl -X POST https://api.fauxlens.com/v1/analyze \
  -H "Authorization: Bearer fxd_live_YOUR_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@photo.jpg"

One call costs 10 credits, the same as one scan in the app.
Your free starting credits cover your first few calls. Already used FauxLens? Your existing balance carries over: the API spends the same credits.

See credit packsEnterprise

The FauxLens AI image detection API provides programmatic access to the same detection checks as the web app via a RESTful interface. The primary endpoint accepts image files, video files or a URL, and returns a structured JSON response containing the verdict, confidence score and a per-layer evidence chain - typically within a few seconds. Authentication is a single bearer token in the Authorization header. There is no request signing, no timestamp header and no signature to compute. Create a key on the keys page, send it as Authorization: Bearer, and you are done. Keys are shown once and stored hashed, so a lost key is revoked and replaced rather than recovered. Your key is server-side only. Responses on the API path carry no CORS headers, so a call from browser code fails with an opaque network error rather than a readable one. That is deliberate - a key in a client bundle is a leaked key. Call the API from your backend, a serverless function or a job runner. Rate limits are applied per key: 20 requests per minute, and 30 per minute across all of one account's keys - issuing more keys raises neither, and an account can hold 5 active keys at a time. There is no monthly request cap, because your credit balance is the quota. Any response that got past authentication - a success, 409, 413, 422 or 429 - carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a 429 carries Retry-After. Supported input formats: JPEG, PNG, WebP, HEIC and AVIF images; MP4, MOV, WebM and MKV video. A developer key is capped at 25MB per request, images and video alike; a URL fetch is capped at 50MB. Enterprise credentials get 200MB. Both multipart form data and a JSON body with a url field are accepted. The API operates on the same model as the web tool - uploaded content is deleted after analysis, not retained. All traffic is encrypted in transit.

One API call costs 10 credits - exactly what one scan costs in the web app. The API spends the same credit balance your account already has, so there is no second wallet, no subscription and no invoice. Credit packs are $2.99 for 500 credits, $9.99 for 2,000 credits, $19.99 for 5,000 credits. Credits are a one-time purchase and do not expire. Your free starting credits cover your first few calls, carried over from the web app if you have already used it rather than granted again. There is no monthly free allowance - the balance is the quota, and when it runs out calls return 402 until you top up. Because the balance is shared, API calls reduce what your web and mobile scans can spend, and vice versa. One number, spent from three places. The credits chip in the site header and in the app is therefore also your API usage meter.

The FauxLens API returns a consistent JSON envelope for every detection request. The verdict lives under a data object, alongside three top-level fields. Write a tolerant parser. New fields may be added to the data object without notice; existing ones will not change meaning inside v1.
{
  "data": {
    "summary": "Likely AI-Generated",
    "confidence_score": 0.94,
    "is_short_circuited": false,
    "evidence_chain": [
      {
        "layer": "Metadata Check",
        "status": "failed",
        "label": "Device Metadata",
        "detail": "No camera metadata present."
      }
    ],
    "short_id": "Ab3cD4eF"
  },
  "request_id": "req_9f2c...",
  "credits_remaining": 1990,
  "idempotent_replay": false
}

A FauxLens verdict is an informational signal. It is not proof of authenticity or veracity, and it should not be the sole basis for a consequential decision - rejecting an applicant, removing an account, denying a claim, or treating a file as evidence. Treat it as one input alongside your own context, and route the decisions that matter to a person who can read the evidence chain. Two properties of the response make that concrete. confidence_score is a ranking signal rather than a calibrated probability, so the threshold you choose is a judgment about which errors you can absorb, not a probability of being wrong. And a verdict that finds no evidence of AI generation is not evidence that a file is human-made - a stripped file, a re-encode and a screenshot all look much like an ordinary photograph to most signals. That is why evidence_chain is part of the envelope rather than an optional extra: a verdict you act on should be one you can trace back to the signals that produced it.

The FauxLens API solves AI image authentication at scale across a growing range of application verticals. Content moderation platforms integrate the API into their upload pipeline to automatically flag AI-generated images before they reach human review queues. Running the API call during upload, in parallel with virus scanning and NSFW classification, adds a few seconds of latency and reduces the volume of synthetic content that reaches moderators. Dating and social platforms use the API to screen profile photos during account creation and again when users update their photos. A confidence threshold that triggers a secondary review step, rather than automatic rejection, minimises false positives while catching the majority of synthetic profiles. Applicant tracking systems used by HR teams trigger an API call when a candidate uploads a headshot, returning a result before the profile is routed to a recruiter. This follows the pattern used with other screening APIs: a call on the upload event, with the result stored as a candidate attribute. E-commerce platforms use the API to verify product listing images, flagging AI-generated placeholder imagery that misrepresents actual products. Catching them at upload prevents disputes and chargebacks downstream. News and media organisations embed API calls into their CMS intake workflow, annotating received images with a confidence score before they reach photo editors. Images above a configurable threshold are held for editorial review before publication.

Two patterns cover the majority of real-world implementations: a one-line curl to prove the key works, and a production client that retries correctly. The Idempotency-Key is the part worth getting right. One key per logical operation, reused across retries of that operation. A 5xx refunds your credits and releases the key, so retrying with the same one gets you a fresh scan rather than a stale verdict - but a key that already paid for a SUCCESSFUL scan is spent, and reusing one for a different file is refused outright rather than returning the earlier file's verdict. For URL-based analysis, send a JSON body with a url field instead of a multipart form. URLs must be HTTPS, private and loopback addresses are refused, and the fetch is capped at 50MB.
# curl, to prove the key works:
#   curl -X POST https://api.fauxlens.com/v1/analyze \
#     -H "Authorization: Bearer fxd_live_YOUR_KEY" \
#     -H "Idempotency-Key: $(uuidgen)" \
#     -F "file=@photo.jpg"

import random, time, uuid
import requests

URL = "https://api.fauxlens.com/v1/analyze"


def analyze(filepath: str, api_key: str, max_retries: int = 3) -> dict:
    # One key per operation, reused across this operation's retries. That is
    # what makes a retry after a network timeout safe: if the first attempt
    # landed, you are served the cached response instead of being charged
    # again.
    idem = str(uuid.uuid4())
    for attempt in range(max_retries):
        with open(filepath, "rb") as f:
            r = requests.post(
                URL,
                headers={"Authorization": f"Bearer {api_key}",
                         "Idempotency-Key": idem},
                files={"file": f},
                timeout=120,
            )
        if r.status_code == 200:
            return r.json()
        if r.status_code in (429, 500, 503):
            # These refund and release the key, so the same one is correct here.
            time.sleep((2 ** attempt) + random.uniform(0, 1))
            continue
        r.raise_for_status()
    raise RuntimeError("max retries exceeded")

Each platform type has established patterns for AI detection API integration that map cleanly to the FauxLens API. Content moderation pipelines: trigger the API call as a synchronous check in your upload handler before writing the file to permanent storage. Store the verdict and confidence score as attributes on your content object. Configure a threshold that routes content to a human review queue rather than auto-publishing. Applicant tracking systems (Greenhouse, Lever, or a custom ATS via webhook): configure a webhook on the candidate photo upload event, pass the photo URL to the URL-based endpoint, and write the returned verdict back to the candidate record as a custom field. Run it asynchronously so it adds no latency to the candidate's upload. Social platforms: on any photo or video upload, enqueue a background job that calls the API and writes the result back to the media record. Surface the confidence score in your moderation dashboard as a column in the review queue. Where C2PA provenance data is also present, cross-reference the two. CMS systems: for WordPress, call the API on the wp_handle_upload hook and store the result as post metadata on the attachment. For Contentful, configure a publish webhook on asset publication, call the API with the asset URL, and write the result back through the Management API. Inconclusive results are worth logging for batch human review rather than triggering automatic actions.

Endpoint POST /v1/analyze on api.fauxlens.com. Send the file as multipart/form-data, or a JSON body with a url field. One image or one video per request. Authentication Authorization: Bearer fxd_live_... - one header, nothing to sign. Enterprise accounts can additionally use HMAC-signed requests for body integrity and replay protection; that is opt-in and documented separately. Sending both a bearer key and HMAC headers on the same request returns 400 ambiguous_auth rather than a silent choice between them. Idempotency Every request must send an Idempotency-Key header - a fresh UUID per logical operation. A successful response is cached for 24 hours against that key, and re-sending it replays the original response with X-Idempotent-Replay: true without charging you again. Reusing a key for a different request returns 409 idempotency_key_reused: the charge is recorded in your credit ledger, not only in the response cache, so a key that has already paid for one scan cannot pay for a second. Response A 200 returns a JSON envelope with a data object and three top-level fields. data.summary is one of exactly four values: "No AI Detected", "Likely Authentic", "Likely AI-Generated", "AI-Generated". Treat these as an ordered scale rather than a boolean. data.confidence_score is a float from 0 to 1 expressing how strongly the evidence supports the verdict - 0.95 means the pipeline is highly confident, not that the image is 95% fake. Treat it as a ranking signal rather than a calibrated probability, and read the evidence chain alongside it. data.is_short_circuited is true when one signal was decisive enough that the remaining layers were skipped, which is why some responses return faster than others. data.evidence_chain is an array of per-layer results, each with layer, status ("passed", "warning" or "failed"), label and a human-readable detail string. This is structured for direct embedding in your own audit logs, so a verdict you show a user can always be traced back to the signals that produced it. data.short_id is an opaque per-scan identifier for your own logs. API scans are deliberately NOT published to the shareable-report surface, so it does not resolve to a fauxlens.com URL - your users' uploads never become public links. request_id is a UUID for support and for your own correlation. credits_remaining is your balance after the call. idempotent_replay is true when the request matched a previous one and you were served the cached verdict without being charged again. Rate limits Any response that got past authentication - a success, 409, 413, 422 or 429 - carries X-RateLimit-Limit (your per-minute budget), X-RateLimit-Remaining (what is left in the current window) and X-RateLimit-Reset (the unix second the window resets). Developer keys are limited to 20 requests per minute. Exceeding it returns 429 with a Retry-After header. Back off exponentially with jitter rather than retrying immediately, and treat 429 as a signal to queue rather than to drop the job. Error codes Errors return a typed envelope rather than a bare string, so you can branch on the code instead of parsing prose. 400 invalid_request_error covers missing_idempotency_key, ambiguous_auth and a malformed body. 401 authentication_error means invalid_api_key - unknown, malformed or revoked. 402 payment_required_error carries the code insufficient_credits and means the balance is below the cost of one call. 403 permission_error appears when a key linked to an enterprise account whose status is not active is used. 409 conflict_error is idempotency_key_reused. 413 request_too_large_error is a body over the size cap, and 415 unsupported_media_type_error is a MIME, extension or codec rejection. 422 invalid_request_error with analysis_failed means the pipeline could not analyse the file, and the credits are refunded. 500 and 503 are api_error; credits are refunded on 500. Credits and refunds Credits are reserved before the model runs, so concurrent calls cannot overdraw the balance. A failed scan - a crash, an analysis_failed verdict, an unhandled error - is refunded automatically and idempotently. You are not charged for a scan you did not get. Handling errors Retry 429, 500 and 503 with exponential backoff. Do not retry the other 4xx codes: a revoked key, an unsupported codec or an exhausted balance will fail identically on a second attempt.

If 20 requests per minute is the constraint rather than the price, that is the signal that you want Enterprise - and moving there does not change your code. Enterprise is the same endpoint, the same request shape and the same response envelope. Buying a tier with the same account links the keys you already have to the enterprise account, and from the next request onward they draw on the enterprise balance at the enterprise rate limit. Nothing to migrate, no key to swap, no deploy. Two things change, and both are visible in the response. credits_remaining starts reporting the enterprise balance. Any credits left in your personal wallet stay there - still spendable in the web and mobile apps, simply no longer what the API draws down. Enterprise additionally offers HMAC request signing, IP allowlists, invoicing and a DPA. Those are opt-in; your bearer keys keep working either way.

Frequently asked questions

Sign in and create a key on the keys page. There is no application form, no qualification call and no waiting for a reply. Your free starting credits cover your first few API calls. Those are the same credits the web tool starts you with - the API adds no free allowance of its own - so if you have used FauxLens on this device already, you begin with whatever is left of them.

One call costs 10 credits, the same as one scan in the web app. Credit packs are $2.99 for 500 credits, $9.99 for 2,000 credits, $19.99 for 5,000 credits. Credits are a one-time purchase, they do not expire, and the API spends the same balance as the website and the Android app.

There is no monthly free allowance. Your free starting credits cover your first few API calls, enough to confirm the integration works before you buy a pack. Those are the same free credits the web app starts you with - the API adds no free allowance of its own - so if you have used FauxLens before, whatever is left carries over to your account. After that every call costs credits, and calls return 402 when the balance runs out.

Developer keys are limited to 20 requests per minute. There is no monthly request cap - your credit balance is the quota. Rate-limited responses return HTTP 429 with a Retry-After header. Implement exponential backoff with jitter, reusing the same Idempotency-Key so the retry cannot double-charge you.

Most images return in a few seconds. Video takes longer and scales with file length and size. Set a generous client timeout - the upload itself dominates on a slow connection, and a large video has to finish uploading before analysis starts.

No. The API path returns no CORS headers, so a browser request fails with an opaque network error. This is deliberate: a bearer key in a client bundle is a leaked key. Call the API from your backend, a serverless function or a job runner, and keep the key server-side.

Revoke it and create another. Keys are shown once and stored hashed, so nobody - including us - can recover one after it is issued. Revocation takes effect on the very next request, and issuing a replacement is free and instant, which is what makes show-once safe to rely on.

Not currently - every request to the analysis endpoint is synchronous and returns the verdict in the same response. Images typically complete in a few seconds; a large video takes longer, so set a client timeout that accommodates the upload as well as the analysis. If an asynchronous callback mode would change how you integrate, tell us and we will scope it against real demand rather than shipping a queue nobody uses.

The FauxLens web tool provides the same forensic analysis as the API without any registration, so you can validate detection quality for your use case before writing integration code. Worth knowing first: the web tool and the API spend the SAME free credits, so scans you run there leave fewer calls for the API. To exercise the API itself you need a key, which requires signing in.

The same endpoint and the same detection engine. The developer tier is self-serve: a bearer token, credit packs from $2.99, and 20 requests per minute. Enterprise adds prepaid volumes (invoiced), higher rate limits, HMAC signing, IP allowlists and a DPA. No code change: your keys link to the enterprise balance.

Not on its own. Use it to prioritize and to route, and keep a person in the loop before any consequential action: rejecting an applicant, removing an account, denying a claim or treating a file as evidence. See "How to Use a Verdict" above for what the response can and cannot support.

Ready to build?

Sign in, create a key, and make your first call. Keys are shown once and can be revoked any time.