Orivfy Text Detection API

Frontend integration guide: REST payloads, WebSockets, secret_key authentication, field semantics, and polar-chart radar_axes[] on both scan endpoints. Relative API prefix: /api/v1.

Authentication

Every REST request must include secret_key matching the server SECRET_KEY in .env. Invalid or missing key: 403.

WebSockets: include secret_key in the first JSON frame.

Endpoints overview

MethodPathPurpose
GET/This integration page (HTML)
GET/api/v1/discovery.jsonDiscovery JSON (machine-readable index)
POST/api/v1/scan/ai-scanPassage-level Human / AI / Uncertain — scores, radar_axes[], optional source_attribution
POST/api/v1/scan/deep-scanSentence-level windows — dual verdicts, radar_axes[] (passage-aligned), scores, labels
POST/api/v1/scan/extract-document-textExtract plain text from PDF / DOCX / txt
POST/api/v1/scan/document-forensicsDocument metadata forensics (PDF / DOCX)
WS/api/v1/explanation/ws/explain-textStreaming forensic text explanation
GET/docsSwagger UI
GET/api/v1/openapi.jsonOpenAPI JSON

Polar charts: POST …/ai-scan and POST …/deep-scan both return radar_axes[] — five heuristic dimensions (integer 0–100 each) keyed for stable UI bindings. Derived from submitted text, passage ai_score, and the verdict probability inferred on the server (same basis as Dashboard confidenceValue). Axis semantics and a reference table → Radar axes.

AI scan (passage)

/api/v1/scan/ai-scan — Full-passage classification: Human, AI, or Uncertain. Legacy field confidence is passage-level P(AI) (same numeric value as ai_score). Response includes radar_axes[] for polar charts (passage-aligned heuristics). Optional source_attribution when the passage is flagged AI (vendor hints: OpenAI, Gemini, Claude).

POST/api/v1/scan/ai-scan

Request JSON

{
  "secret_key": "<server SECRET_KEY from .env>",
  "text": "Your passage …",
  "config": null
}
  • secret_key — Required; must match server SECRET_KEY.
  • text — Required UTF-8 string.
  • config — Optional ParameterConfig (threshold, batch_size, context_sentences, …).

Response JSON · AIScanResponse (illustrative)

{
  "prediction": "AI",
  "confidence": 0.71,
  "is_mixed": false,
  "is_ai": true,
  "ai_score": 0.71,
  "mixed_score": 0.0,
  "human_score": 0.29,
  "radar_axes": [
    {"key": "ai_signal", "label": "AI Signal", "value": 71},
    {"key": "uniformity", "label": "Uniformity", "value": 62},
    {"key": "confidence", "label": "Confidence", "value": 71},
    {"key": "perplexity", "label": "Perplexity", "value": 54},
    {"key": "burstiness", "label": "Burstiness", "value": 58}
  ],
  "source_attribution": {
    "status": "ok",
    "likely_source": "openai",
    "likely_label": "OpenAI",
    "confidence": 0.42,
    "margin": 0.11,
    "candidates": [
      {"source": "openai", "label": "OpenAI", "score": 0.42},
      {"source": "gemini", "label": "Google Gemini", "score": 0.28}
    ],
    "source_display": {
      "kind": "single",
      "options": [{"source": "openai", "label": "OpenAI · ChatGPT"}],
      "show_confidence": true
    },
    "evidence": ["HF RoBERTa ChatGPT-detector affinity ≈ 62%"],
    "method": "hf_chatgpt_roberta+lmscan",
    "word_count": 312,
    "detail": null
  }
}
  • mixed_score — Always 0 on AI-only passage scan.
  • radar_axes — Always five facets (key, label, integer value); see Radar axes.

Deep scan (sentences)

/api/v1/scan/deep-scan — Sentence windows with neighbor context; each row exposes prediction, ai_probability (P(AI)), and optional model fields when enabled. Passage-level P(AI) appears as ai_score (alongside human_score). Dual verdicts: passage_verdict + distribution_verdict; distribution_confidence tiers the sentence-mix label. radar_axes[] mirrors the passage headline (same inputs as AI scan)—not recomputed from raw sentence-frequency counts alone.

POST/api/v1/scan/deep-scan

Request JSON

{
  "secret_key": "<server SECRET_KEY from .env>",
  "text": "Your document …",
  "config": null
}

Response JSON · DeepScanResponse (illustrative)

{
  "sentences": [
    {
      "sentence": "…",
      "prediction": "AI",
      "ai_probability": 0.94
    }
  ],
  "distribution_confidence": 0.72,
  "passage_verdict": "AI",
  "distribution_verdict": "AIWrittenHumanModified",
  "deep_labels": ["AI", "AIWrittenHumanModified"],
  "overall_prediction": "AI",
  "is_mixed": false,
  "mixed_ratio": 0.45,
  "ai_score": 0.71,
  "mixed_score": 0.12,
  "uncertain_sentence_ratio": 0.12,
  "human_score": 0.29,
  "radar_axes": [
    {"key": "ai_signal", "label": "AI Signal", "value": 71},
    {"key": "uniformity", "label": "Uniformity", "value": 62},
    {"key": "confidence", "label": "Confidence", "value": 68},
    {"key": "perplexity", "label": "Perplexity", "value": 54},
    {"key": "burstiness", "label": "Burstiness", "value": 58}
  ],
  "source_attribution": { }
}
  • passage_verdict — Same rule as AI scan: Human · AI · Uncertain.
  • distribution_verdict — Sentence-mix label (see semantics).
  • deep_labels[passage_verdict, distribution_verdict].
  • ai_score / human_score — Passage-level P(AI) / P(Human); no duplicate “overall_*” aliases.
  • distribution_confidence — Verdict-facing blend (passage + sentence AI rate).
  • radar_axes — Five chart facets aligned with passage model + text heuristics; see Radar axes.

Documents

POST/api/v1/scan/extract-document-text

Multipart: secret_key (form) + file — PDF, DOCX, txt, md. Returns text, word_count, filename.

POST/api/v1/scan/document-forensics

Multipart: secret_key (form) + file — Metadata forensics (AI-tool fingerprints, editing anomalies, timestamps, fonts). No neural text classifier.

{
  "doc_type": "docx",
  "filename": "report.docx",
  "suspicion_score": 0.34,
  "verdict": "Inconclusive",
  "signals": [ ],
  "editing_behaviour": { },
  "summary": "…"
}

WebSocket · explanations

Open WebSocket → send one JSON text frame. Use wss: when API is HTTPS.

WS/api/v1/explanation/ws/explain-text

First message JSON (derive from POST …/deep-scan)

{
  "secret_key": "…",
  "prediction": "AI",
  "overall_prediction": "AI",
  "passage_verdict": "AI",
  "distribution_verdict": "AIWrittenHumanModified",
  "confidence": 0.71,
  "distribution_confidence": 0.72,
  "text": "",
  "ai_score": 0.71,
  "human_score": 0.29,
  "mixed_score": 0.12,
  "radar_axes": [
    {"key": "ai_signal", "label": "AI Signal", "value": 71},
    {"key": "uniformity", "label": "Uniformity", "value": 62},
    {"key": "confidence", "label": "Confidence", "value": 68},
    {"key": "perplexity", "label": "Perplexity", "value": 54},
    {"key": "burstiness", "label": "Burstiness", "value": 58}
  ],
  "sentences": [
    {
      "sentence": "…",
      "prediction": "Human",
      "ai_probability": 0.19
    }
  ]
}
  • For explanations, reuse passage P(AI) as confidence (same number as scan ai_score); include distribution_prediction when using deep-scan mode.
  • Server excerpts high-P(AI) snippets for Gemini; keep text empty or short.
  • You may copy additional fields returned by POST …/deep-scan (same shape as REST), including radar_axes — the WS handler ignores facets it does not need.

Frames from server

  • start — beginning
  • chunkcontent, partial_text
  • completefinal_text
  • errormessage

Field semantics

FieldMeaning
prediction / passage_verdictHuman · AI · Uncertain (passage-level)
distribution_verdictSentence-mix label (see table below)
deep_labels[passage_verdict, distribution_verdict]
is_aiTrue when passage is AI or Uncertain (AI scan only)
distribution_confidenceBlended 0–1 score for distribution verdict (deep scan)
confidence (AI scan)Passage P(AI); same numeric value as ai_score
ai_scorePassage P(AI) (recommended for new clients)
mixed_ratioFraction of sentences classified AI
mixed_score / uncertain_sentence_ratioFraction of sentences with 0.45 ≤ P(AI) ≤ 0.55
source_attributionVendor hints when passage is AI (≥50 words)
sentence[].*sentence, prediction, ai_probability (and optional extras when the model returns them)
radar_axes[]AI scan & deep scan: five objects { key, label, value } with integer value 0–100 for polar charts; see axis table

Privacy: scans processed in memory; benchmarks only under evaluation_results/.

Labels & confidence

Passage verdict (AI scan & deep scan)

From passage P(AI) vs server threshold ± mixed_offset (default 0.5 ± 0.05):

On AI scan responses, confidence and ai_score are the same passage-level P(AI) (kept under both names only for backwards compatibility).

Distribution verdict (deep scan only)

Derived from distribution_confidence (0.6 × passage certainty + 0.4 × sentence AI rate):

BandAI passageHuman passage
≥ 0.75AIHuman
0.55 – 0.75AIWrittenHumanModifiedHumanWrittenAIModified
0.45 – 0.55Uncertain
< 0.45HumanWrittenAIModifiedAIWrittenHumanModified

Source attribution

When passage verdict is AI and text has ≥ 50 words: fused lmscan stylometrics + optional HF ChatGPT-detector. UI should prefer source_display (single, dual, or uncertain) over raw candidates.

Sentence rows

Radar axes (radar_axes[])

Five deterministic 0–100 integers for polar / spider charts—not extra classifier endpoints. Derived from submitted text, passage-scale ai_score (P(AI)) and the headline verdict probability produced during inference on the wire (aligned with Dashboard confidenceValue rounding).

keyLabelInterpretation
ai_signalAI SignalPassage AI tendency: ai_score × 100, capped 0–100.
uniformityUniformitySimilarity of sentence lengths (inverse of coefficient of variation). Higher = more regular lengths; lower = more human-like variation.
confidenceConfidenceVerdict-facing facet from headline probability, scaled to one decimal percent then 0–100 (matches product radar).
perplexityPerplexity (proxy)Lexical heuristic (CTTR-style diversity plus average English token length), not token-level LM perplexity.
burstinessBurstinessSpacing variance of repeated words (gap variance vs average gap). Higher suggests more “bursty” natural rhythm vs flat repetition.

For UI parity, render radar_axes alongside headline verdict, deep labels (when present), and sentence tallies so charts stay in sync with copy and meters.

Swagger · OpenAPI

/docs · Schema /api/v1/openapi.json