HTTP API
Two public endpoints: POST /api/scan (detect AI-writing signals) and POST /api/cleanup (strip machine typography, no rewriting). Base URL https://api.scanforai.com. Anonymous works; an API key raises your limits and saves history. The score is a signal, not a verdict.
Authentication
Send an API key (minted in the dashboard) as a bearer token — same header on every request:
Authorization: Bearer at_sk_your_key_here
Scripted/API calls need a key — registration is free (no card) and takes a minute. Anonymous access is reserved for the web scanner and the browser extension. Key scopes: full, or read (scan/read only). Your current usage-vs-limits and recent request statuses are on the dashboard's API-keys page.
POST /api/scan
Body can be JSON, a form field, or raw text. Quickest taste — pipe a file in, get a human-readable report back:
# plain-text report, straight from a file:
curl -s --data-binary @draft.txt -H 'Authorization: Bearer at_sk_...' \
"https://api.scanforai.com/api/scan?format=text"
# JSON (a JSON body overrides the query-param knobs):
curl -s https://api.scanforai.com/api/scan \
-H 'Authorization: Bearer at_sk_...' \
-H 'Content-Type: application/json' \
-d '{"text": "...", "include_fixes": true}'
# file upload (multipart; .txt .md .html .docx .pdf, extracted server-side, 1 MB max):
curl -s -F "file=@essay.docx" -H 'Authorization: Bearer at_sk_...' \
https://api.scanforai.com/api/scan Parameters (JSON body):
text— the text to scan (required unless you upload afile).include_fixes(bool, default true) — return "top fixes" suggestions.genre(string) — a register hint (academic,expository,fiction) so formal writing isn't over-flagged.esl(bool, default false) — the writer's first language isn't English. Relaxes the formality tells that non-native writing shares with AI, independently ofgenre— so an ESL essay keeps its essay scoring and is judged more fairly. The response echoesesland a matchinggenre_note.deep(bool, default false, account only) — also run the deeper model on long text.save(bool, default true, account only) — store to history;falseopts out. Anonymous scans are never stored.title,parent_scan_id(account only) — label / revision chain.
Response (fields are stable; new ones may be added):
{
"score": 68.4, // 0..100, higher = more AI-like — NOT a probability
"band": "elevated", // low | moderate | elevated | high
"label": "strong signs of AI writing",
"confidence": "high", // high | moderate | low — how far to trust THIS read
"confidence_note": "a clear, consistent signal across enough text",
"model_used": false, // whether the deeper model was part of this scan
"word_count": 1240,
"coverage": {"active_signals": 11, "total_signals": 12, "words": 1240},
"signals": [ {"name": "sentence_rhythm", "score": 0.82, "weight": 3.0,
"detail": "sentences are unusually even in length", "value": 0.24}, ... ],
"fixes": ["vary sentence length: ...", ...],
"scan_id": null, // an account + save:true returns the stored id
"disclaimer": "A signal, not a verdict. ..."
} Errors: 413 over the character cap, 429 rate-limited (message includes retry seconds), 402 monthly word quota reached, 422 empty text. If the model worker is briefly unavailable the scan still succeeds heuristics-only, with "model_used": false and a "degraded" note.
POST /api/cleanup
Strips machine-typography artifacts and normalizes to plain text without rewriting a word (deterministic). The deeper detector-guided rewrite ("Humanize") is a separate, future endpoint.
curl -s https://api.scanforai.com/api/cleanup \
-H 'Authorization: Bearer at_sk_...' \
-H 'Content-Type: application/json' \
-d '{"text": "The results—truly—are “remarkable”…"}' Parameters: text (required), contractions (bool, default false — also apply everyday contractions), and account-only title / save (saved to history like scans).
{
"mode": "light",
"output_text": "The results - truly - are \"remarkable\"...",
"changes": {"em/en dash": 2, "smart quotes": 2, "ellipsis glyph": 1},
"total_changes": 5,
"chars_in": 40, "chars_out": 41,
"id": null // an account + save:true returns the stored id
} GET /api/config
Your tier's limits (what the counter uses): char cap, monthly word quota + usage, per-hour caps, and whether the deep model is available to you.
Accounts & API keys
A free account (dashboard) raises the per-scan limit to 50,000 characters, adds a monthly word quota, saves scan + cleanup history, and issues API keys. Authenticated scans/cleanups are saved by default — pass "save": false to opt out.
Fair use
Please don't wrap this in a product that presents scores as verdicts about people. The response's disclaimer field exists to be shown.