AI Detection API: How to Integrate AI Content Scanning Into Your Workflow
- ai-detection
- api
- integration
- developers
- workflow
A developer-focused guide to integrating SynthQuery’s AI detection API: endpoints, auth, rate limits, Python/Node/cURL examples, WordPress and Google Docs patterns, batch jobs, score thresholds, and pricing-aware optimization.
Integrating AI detection via API lets you run the same scoring your editors see in the browser inside CMS pipelines, LMS hand-ins, and moderation queues—without copy-pasting drafts into a separate tab. This guide is for developers, CTOs, and content operations leads who need a concrete integration map, not marketing fluff.
For how classifier scores behave in the real world (and what they cannot prove), pair this with How to detect AI-generated content and ChatGPT detection limitations.
Table of contents
- Use cases for API integration
- SynthQuery API overview
- Code examples: Python, Node.js, and cURL
- API response shape (reference)
- Building a WordPress plugin
- Google Docs via Apps Script
- Batch processing for large libraries
- Interpreting scores and thresholds
- Webhooks and async-style processing
- Checklist before production
- Best practices: caching, errors, rate limits
- Pricing tiers and usage optimization
- Performance benchmarks (indicative)
Use cases for API integration
CMS and editorial plugins
Hook detection into save, schedule, or publish transitions so editors get feedback before content goes live. A common pattern: run standard mode on every save, escalate to DeepScan when the score crosses a threshold or when the piece is marked “high risk” (finance, health, legal).
Editorial workflows (Git, review tools, Notion exports)
Teams that draft in Google Docs, Notion, or Markdown repos can call the API from a CI check or a review bot so “AI likelihood” sits next to spelling and readability—without blocking the human reviewer from overriding the result.
LMS and academic platforms
Learning platforms can scan submissions after upload and route high scores to a second review queue. Policy still lives with the institution; the API supplies a triage signal, not a misconduct verdict.
Trust and safety / UGC moderation
Marketplaces and communities can score user-generated descriptions in batch workers, combining AI detection with plagiarism and human review for borderline cases.
SynthQuery API overview
Base URL and endpoint
Production traffic goes through the Next.js proxy (never call FastAPI directly from a browser—secrets stay server-side). The detection endpoint is:
POST /api/v1/detect
Resolve it against your app host, for example https://yourapp.com/api/v1/detect. The interactive AI Detector uses the same route. OpenAPI metadata is published at /api/openapi.json alongside the broader API docs surface.
Authentication and sessions
The handler uses Supabase session cookies (createServerClient in the API route). Practically:
- Browser / same-origin apps: Call
POST /api/v1/detectwithfetch(..., { credentials: "include" })while the user is signed in—cookies attach automatically. - Server-side or custom integrations: Forward a valid session Cookie header from your trusted proxy, or perform the detection from the browser after login. Workspace API keys (
sq_…) are issued from Dashboard → API Keys for roadmap/SDK flows; wire them through your backend until your deployment documents key-based auth on this route. - Anonymous try-outs: A small number of unauthenticated requests per IP are allowed for smoke tests (see Rate limits). Production traffic should use signed-in accounts so you get higher limits and optional
analysis_idpersistence.
Related endpoints
GET /api/v1/detect/languages— supported and recommended language codes (rate-limited per IP).- Responses may include
analysis_idfor authenticated users when history storage succeeds.
Request body
| Field | Type | Notes |
| --- | --- | --- |
| text | string | Required. Min 20 characters, max 100,000 characters. |
| mode | "standard" | "deepscan" | Optional. deepscan requests a deeper analysis path; availability ties to plan. |
| language_hint | string or null | Optional ISO 639-1 hint (e.g. en). |
Rate limits
Limits combine per-plan character budgets in a sliding window and anonymous IP caps:
- Anonymous: up to 3 detection runs per IP per rolling window (when Redis is configured), and 15,000 characters per request.
- Authenticated: character budgets depend on plan (see Pricing tiers). The API returns
X-RateLimit-*headers for signed-in traffic when applicable.
Always backoff on 429 responses and surface a clear message to editors.
Code examples: Python, Node.js, and cURL
Replace placeholders with your host, API key, and sample text. These examples assume HTTPS and a JSON body.
Python
import os
import requests
API_URL = "https://yourapp.com/api/v1/detect"
API_KEY = os.environ["SYNTHQUERY_API_KEY"] # sq_...
payload = {
"text": "Paste at least twenty characters of sample copy here. "
"Longer samples stabilize classifier estimates.",
"mode": "standard",
"language_hint": "en",
}
r = requests.post(
API_URL,
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
r.raise_for_status()
data = r.json()
print("overall_score:", data["overall_score"])
print("confidence:", data["confidence"])
JavaScript (Node.js)
import process from "node:process";
const API_URL = "https://yourapp.com/api/v1/detect";
const API_KEY = process.env.SYNTHQUERY_API_KEY;
const payload = {
text:
"Paste at least twenty characters of sample copy here. " +
"Longer samples stabilize classifier estimates.",
mode: "standard",
language_hint: "en",
};
const res = await fetch(API_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (!res.ok) {
const err = await res.text();
throw new Error(`Detect failed ${res.status}: ${err}`);
}
const data = await res.json();
console.log("overall_score", data.overall_score);
console.log("confidence", data.confidence);
cURL
curl -sS -X POST "https://yourapp.com/api/v1/detect" \
-H "Authorization: Bearer $SYNTHQUERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Paste at least twenty characters of sample copy here. Longer samples stabilize classifier estimates.",
"mode": "standard",
"language_hint": "en"
}'
API response shape reference
The API returns a JSON object aligned with the DetectionResult model: an overall probability, sentence-level scores, attribution heuristics, and optional language metadata.
Response schema (diagram)
DetectionResult
├── overall_score: number # 0–1 AI probability (aggregate)
├── sentences: Sentence[]
│ ├── text: string
│ ├── start: number # char offset in original
│ ├── end: number
│ ├── score: number # 0–1 per sentence
│ └── is_ai: boolean # true when score > 0.6 (server default)
├── model_attribution: string # heuristic label (e.g. family / unknown)
├── confidence: string # "high" | "medium" (overall confidence band)
├── model_version?: string
├── cache_hit?: boolean
├── attribution_phrases?: string[]
├── detected_language?: string # ISO 639-1 when available
├── language_supported?: boolean
├── segment_count?: number
├── processing_time_ms?: number
├── low_confidence?: boolean
├── style_signals?: object # buckets like meta_phrases, connectors, …
└── analysis_id?: string # when persisted for authenticated users
Architecture: AI detection in an editorial workflow
┌──────────────────┐
│ Author draft │
│ (Docs / CMS / IDE)│
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Save / publish │
│ webhook │
└────────┬─────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌────────────────┐ ┌────────────────┐
│ Queue / batch │ │ Inline API │
│ worker (bulk) │ │ (interactive) │
└────────┬───────┘ └────────┬───────┘
│ │
└──────────────┬──────────────┘
▼
┌──────────────────┐
│ POST /api/v1/ │
│ detect │
└────────┬─────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌────────────────┐ ┌────────────────┐
│ Score + heatmap│ │ Notifications │
│ in CMS sidebar │ │ (Slack / email)│
└────────────────┘ └────────────────┘
Mermaid source (paste into mermaid.live if you want a vector diagram for slides):
flowchart TD
A[Author draft] --> B[CMS save / webhook]
B --> C{Inline or batch?}
C -->|Interactive| D[POST /api/v1/detect]
C -->|Bulk| E[Queue worker]
E --> D
D --> F[JSON: scores + sentences]
F --> G[CMS sidebar / Slack / warehouse]
Building a WordPress plugin
Goals
- Add a meta box or sidebar panel that runs when a post transitions to
pendingorpublish. - Store the latest overall score and timestamp in post meta for auditing.
- Respect rate limits: batch scans off the request path when possible.
Outline (PHP)
- Register a REST route inside WordPress that your UI calls, e.g.
POST /wp-json/synthquery/v1/scan. - That route uses
wp_remote_post()to call SynthQuery with server-stored session credentials or a dedicated proxy (never expose secrets to the block editor). - Map the JSON response into post meta:
_sq_ai_score,_sq_ai_confidence,_sq_ai_checked_at. - Optionally add a Capabilities check (
edit_posts) before scanning.
Keep the secret in wp-config.php constants or the encrypted options API—not in version control.
Google Docs via Apps Script
Apps Script can send drafts to your integration endpoint:
- Add a custom menu (“SynthQuery → Scan selection”).
- Read the active selection (or whole doc body) with the Document API.
UrlFetchApp.fetch()your WordPress REST proxy or a small Cloud Run function that holds credentials—avoid embedding secrets in the script source for shared docs.- Write results to a sidebar (
HtmlService) showingoverall_scoreand top flagged sentences.
Because Docs scripts run under the end-user Google account, the secure pattern is: Apps Script → your backend → SynthQuery—not Apps Script → SynthQuery with a raw key in client code.
If you need per-paragraph highlights, request the full sentences array from your backend and map start/end offsets back onto the Docs selection in a sidebar—keep heavy rendering client-side while the credential stays server-side.
Batch processing for large libraries
Chunking
- Stay under the 100,000 character cap per request; split long PDF extracts on paragraph boundaries.
- Deduplicate chunks with a hash so you do not pay twice for identical blocks during re-imports.
- Prefer paragraph-aware splitting: breaking mid-sentence can shift token statistics and produce noisier scores at boundaries.
Orchestration
Use BullMQ, Celery, Sidekiq, or cloud schedulers. Each job should:
- Pull the next document from the queue.
POST /api/v1/detectwithmodeappropriate to policy (standardfor screening,deepscanfor escalations).- Persist
{ docId, overall_score, confidence, processing_time_ms }to your warehouse. - On 429, exponential backoff with jitter; on 5xx, retry with a cap.
Worker pseudocode for a resilient consumer:
while True:
doc = queue.blocking_pop(timeout=30)
if doc is None:
continue
chunks = split_paragraphs(doc.body, max_chars=95_000)
scores = []
for chunk in chunks:
resp = http_post_detect(chunk, mode=policy.mode_for(doc))
if resp.status == 429:
queue.requeue_front(doc, delay=backoff_with_jitter())
break
if resp.status >= 500:
queue.retry(doc, err=resp.body)
break
scores.append(resp.json["overall_score"])
else:
store_result(doc.id, aggregate_scores(scores))
Idempotency
Store a content hash → result mapping in Redis or your DB so editorial tweaks that revert text do not trigger redundant model work when your stack allows caching.
Designing a secure integration boundary
Treat SynthQuery like any third-party ML endpoint:
- Minimize data: send only the text you must score; strip signatures, internal comment threads, and unrelated PII when policy allows.
- Transport: HTTPS only; pin certificates if your compliance program requires it.
- Secrets: session material stays in vaults or managed secrets—never in client-side Apps Script or theme files.
- Audit: log who triggered a scan (editor id, CMS revision), not just the numeric score—your governance team will ask why something was flagged.
- Retention: align storage of returned JSON with your privacy policy; sentence-level arrays can be large—compress or truncate cold storage if you only need aggregates after 90 days.
Interpreting scores and thresholds
The UI maps roughly to:
- Likely human:
overall_score < 0.3 - Mixed:
0.3 ≤ overall_score < 0.6 - Likely AI-generated:
overall_score ≥ 0.6
Per-sentence rows set is_ai when score > 0.6. Your organization can adopt stricter thresholds for auto-flagging (e.g. escalate only when overall_score ≥ 0.75).
Treat confidence and low_confidence as gating signals: short boilerplate, translated text, or languages outside the recommended set may inflate uncertainty—pair scores with human review for high-stakes content.
Webhooks and async-style processing
The HTTP API is synchronous: you receive the full JSON when the request completes. “Async” patterns are built around the API:
- Job queue + worker pulls from your CMS webhook, calls the API, then POSTs to your own Slack webhook or case-management system.
- Polling from a dashboard if you store
analysis_idclient-side. - Enterprise teams sometimes need signed callbacks from a vendor—if your procurement requires vendor-originated webhooks, route them through your integration layer so secrets and SLAs stay under your control.
Concrete CMS pattern: register save_post (WordPress) or an equivalent content.publish.requested hook → enqueue { postId, revision } → worker calls POST /api/v1/detect → on success, update meta and optionally POST to https://hooks.slack.com/... with { text, overall_score, edit_url }. The SynthQuery side does not need to know Slack exists; your worker is the orchestration point.
Checklist before production
- [ ] Thresholds documented with legal/editorial—not only engineering.
- [ ] 429/5xx handling verified under load tests.
- [ ] Secrets rotation path for any proxy that stores session material.
- [ ] Data map updated: what text leaves your perimeter and where results land.
- [ ] DeepScan gated to plans that include it in Pricing.
Best practices: caching, errors, rate limits
Caching
- Respect
cache_hitwhen present: identical payloads may be cheaper end-to-end. - On your side, cache by hash for repeated strings during bulk reprocessing.
Error handling
| Status | Meaning | Action | | --- | --- | --- | | 400 | Bad payload (too short, malformed JSON) | Fix validation; min 20 chars. | | 413 | Too large for tier / anonymous | Chunk text or upgrade plan. | | 429 | Throttled | Backoff; surface “try later” in UI. | | 502/503 | Upstream unavailable | Retry with cap; alert ops. |
Log request_id if you add one at your proxy; correlate with FastAPI logs on self-hosted stacks.
Rate limiting client-side
- Token bucket in your worker pool so you do not stampede the API at cron boundaries.
- Shuffle large backfills to spread load.
Pricing tiers and usage optimization
SynthQuery publishes list pricing on the Pricing page. High-signal points for API consumers:
| Plan | Typical API positioning | | --- | --- | | Free | Try flows; tight per-request and hourly character caps for detection. | | Starter | Higher per-request ceiling for long articles. | | Pro | DeepScan and API access for production integrations. | | Expert / Enterprise | Very large or unlimited character budgets; Enterprise adds custom limits, SLA, and SSO. |
Optimization tactics
- Run standard mode for first-pass triage; reserve DeepScan for escalations.
- Pre-filter tiny edits: skip API calls when only a few words changed but the document hash is unchanged.
- Schedule heavy batch jobs off peak editorial hours to reduce contention with interactive users sharing the same workspace.
Performance benchmarks (indicative)
Laboratory-style numbers vary by region, hardware, cache state, and text length. Use these order-of-magnitude figures for capacity planning, then measure against your own deployment.
| Scenario | Typical latency | Notes | | --- | --- | --- | | Warm, cached hit | Under 50 ms additional server time | Redis cache in the detection path. | | Standard mode, ~1–2k words | 150–600 ms | Dominated by model inference + tokenization. | | DeepScan, long article | 0.7–2.5 s | Heavier analysis path; still one HTTP round trip. | | Throughput per workspace | Plan-limited | Sliding window of characters per hour per user—not unbounded QPS. |
For throughput, assume serial calls unless you run multiple workers and your plan tolerates the aggregate character volume. Horizontal scale on the client side does not bypass per-account fairness limits.
In production, capture p50/p95 latency and 429 rate from your integration tier—these numbers matter more than synthetic benchmarks because they include your network path, TLS, and queue wait times.
Bottom line: wire POST /api/v1/detect behind your CMS or LMS, treat scores as triage, and engineer retries, backoff, and hashing the way you would for any paid ML API. When you are ready to ship, align stakeholders on thresholds, document your escalation path, and keep humans in the loop for anything that touches policy or publication risk. Revisit this guide when your team adds new channels (video transcripts, support macros, localized sites)—the integration pattern stays the same even as content shapes diversify.
Itamar Haim
SEO & GEO Lead, SynthQuery
Founder of SynthQuery and SEO/GEO lead. He helps teams ship content that reads well to humans and holds up under AI-assisted search and detection workflows.
He has led organic growth and content strategy engagements with companies including Elementor, Yotpo, and Imagen AI, combining technical SEO with editorial quality.
He writes SynthQuery's public guides on E-E-A-T, AI detection limits, and readability so editorial teams can align practice with how search and generative systems evaluate content.
Related Posts
What Is SynthID? Google's Multimodal AI Watermarking Explained
SynthID is Google DeepMind's watermarking and provenance technology for AI-generated images, audio, and video—not a generic 'AI detector.' Here's what it does, how it differs from statistical text checks, and what it means for publishers.
AI Content Detection in Journalism: How Newsrooms Verify Source Material
How journalism organizations use AI detection, wire-service policies, ethics codes, and workflows to protect trust—from breaking news to tips and comments—without treating classifiers as proof.
ChatGPT vs Claude vs Gemini: Which AI Is Hardest to Detect in 2026?
A comparative look at how GPT, Claude, Gemini, Llama, and Mistral shape text—and what that means for detect ChatGPT vs Claude vs Gemini workflows, detector scores, and responsible review.
Get the best of SynthQuery
Tips on readability, AI detection, and content strategy. No spam.