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.

Interactive docs & Postman. Live, always-accurate reference with a "try it" console: Swagger UI. Machine-readable spec: openapi.json — paste that URL straight into Postman or Insomnia (Import → Link) to get every endpoint and parameter as a ready collection.

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):

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.