REST API

X-RAY API Reference

Integrate AI image detection directly into your applications. A single POST request returns a full forensic verdict in under 2 seconds.

Base URLhttps://xray-ai.xyz

Introduction

The X-RAY API allows you to programmatically analyze images for AI-generated content. All requests must be authenticated with an API key. API access is available on Pro and Enterprise plans.

Response format
JSON
Content type
multipart/form-data
Max image size
20 MB
Supported formats
JPG · PNG · WebP · HEIC

Authentication

Pass your API key in the Authorization header as a Bearer token. Generate keys from your cabinet under the API tab.

HTTP
Authorization: Bearer xray_sk_your_api_key_here
cURL
curl -X POST https://xray-ai.xyz/analyze \
  -H "Authorization: Bearer xray_sk_your_api_key_here" \
  -H "Content-Type: multipart/form-data" \
  -F "[email protected]"

Analyze Image

POST/analyzeAnalyze an image for AI-generated content

Submit an image file and receive a full forensic analysis result. The response includes a verdict, confidence score, and per-signal breakdown.

Request

ParameterTypeDescription
imageFileImage file to analyze (required)

Response

JSON
{
  "verdict": "Real Photo",
  "is_ai": false,
  "confidence": 56.5,
  "composite": 51.4,
  "signals": [
    {
      "name": "Primary Neural",
      "key": "primaryNeural",
      "level": "hi",
      "score": 51.1,
      "model": "· DINOv2 + EfficientNet",
      "desc": "Deep neural network trained on millions of real and AI-generated images. Primary verdict driver.",
      "interp": "Model is highly confident this image was generated by an AI system."
    },
    {
      "name": "Secondary Neural",
      "key": "secondaryNeural",
      "level": "hi",
      "score": 69.3,
      "model": "· ViT",
      "desc": "Vision Transformer trained on GAN, diffusion, and real image datasets. Cross-validates the primary model.",
      "interp": "Secondary model confirms AI generation — double consensus detected."
    },
    {
      "name": "Frequency Anomaly",
      "key": "frequencyAnomaly",
      "level": "lo",
      "score": 45.4,
      "model": "FFT spectrum analysis",
      "desc": "FFT spatial frequency analysis. AI images have smoother spectra. JPEG compression can mimic this.",
      "interp": "Natural frequency distribution consistent with real camera optics."
    },
    {
      "name": "Noise Distribution",
      "key": "noiseDistribution",
      "level": "lo",
      "score": 23.9,
      "model": "Block-wise variance analysis · 16×16 px",
      "desc": "Measures spatial unevenness of pixel noise. Real cameras produce scene-dependent noise.",
      "interp": "Natural, scene-dependent noise variance — strong real-camera indicator."
    },
    {
      "name": "Color Coherence",
      "key": "colorCoherence",
      "level": "lo",
      "score": 32.0,
      "model": "Pearson cross-channel RGB correlation",
      "desc": "Measures R/G/B channel correlation. AI generators often produce overly correlated channels.",
      "interp": "Natural channel independence consistent with real photography."
    }
  ],
  "meta": {
    "width": 1280,
    "height": 720,
    "file_size": 115335,
    "format": "image/jpeg",
    "filename": "photo.jpg"
  },
  "usage": {
    "used": 4,
    "limit": 500,
    "role": "pro"
  }
}

Examples

Python
import requests

API_KEY = "xray_sk_your_api_key_here"
BASE    = "https://xray-ai.xyz"

with open("photo.jpg", "rb") as f:
    resp = requests.post(
        f"{BASE}/analyze",
        headers={"Authorization": f"Bearer {API_KEY}"},
        # Content-Type: multipart/form-data (with boundary) is set by requests automatically.
        # Do NOT set it manually — the boundary would be lost and the request would fail.
        files={"image": ("photo.jpg", f, "image/jpeg")},
    )

data = resp.json()
print(f"Verdict: {'AI' if data['is_ai'] else 'Real'}")
print(f"Confidence: {data['confidence']:.1f}%")
JavaScript
const API_KEY = "xray_sk_your_api_key_here";
const BASE    = "https://xray-ai.xyz";

async function analyzeImage(file) {
  // FormData automatically sets Content-Type: multipart/form-data with boundary
  const form = new FormData();
  form.append("image", file);

  const resp = await fetch(`${BASE}/analyze`, {
    method: "POST",
    headers: { Authorization: `Bearer ${API_KEY}` },
    // Do NOT set Content-Type manually — browser sets it with the correct boundary
    body: form,
  });

  const data = await resp.json();
  console.log(`Verdict: ${data.is_ai ? "AI" : "Real"}`);
  console.log(`Confidence: ${data.confidence.toFixed(1)}%`);
  return data;
}

Check Usage

Query your current subscription plan, monthly check limit, and remaining checks. Useful for building usage dashboards or enforcing client-side quotas.

GET/me/usageGet current plan and check usage
cURL
curl https://xray-ai.xyz/me/usage \
  -H "Authorization: Bearer xray_sk_your_api_key_here"

Response

JSON
{
  "plan": "pro",
  "checks_used": 47,
  "checks_limit": 500,
  "remaining": 453
}
FieldTypeDescription
planstringSubscription role: pro, enterprise, admin
checks_usedintegerChecks consumed this month
checks_limitintegerMonthly limit (0 = unlimited)
remaininginteger | nullChecks left this month (null = unlimited)
Python
import requests

resp = requests.get(
    "https://xray-ai.xyz/me/usage",
    headers={"Authorization": "Bearer xray_sk_your_api_key_here"},
)
data = resp.json()
print(f"Plan: {data['plan']}")
print(f"Used: {data['checks_used']} / {data['checks_limit'] or '∞'}")
if data['remaining'] is not None:
    print(f"Remaining: {data['remaining']}")

Errors

The API uses standard HTTP status codes. Error responses include a detail field.

StatusMeaningCommon cause
400Bad RequestInvalid file type or missing field
401UnauthorizedMissing or invalid API key
403ForbiddenPlan does not include API access
413Too LargeImage exceeds 20 MB limit
429Rate LimitedMonthly check quota exceeded
500Server ErrorInternal error — retry after a moment
JSON
{
  "detail": "Monthly check limit reached"
}

Rate Limits

Check limits are shared between dashboard usage and API calls.

PlanChecks / monthAPI keys
Free20
Pro500Up to 3
EnterpriseCustomUp to 10

Check limits are shared between dashboard and API usage. Use GET /me/usage to query your current quota in real time.