Detection reference

Check how
a text reads

A check reads a text with our AI detector and reports how likely it is to be AI-written, which paragraphs carry that, and the writing signals behind it. Checks run in the background, like runs. Each one is charged a small fixed price, held when it starts.

Asynchronous checksNeeds the detect scope
On this page
POST

/v1/detections

Starts a check and returns 202 Accepted. The API key needs the detect scope (see Authentication); without it the response is 403 insufficient_scope. Limited to 10 requests per minute per key.

Check a textcURL
curl https://humanizeword.com/api/v1/detections \
  -H "Authorization: Bearer $HUMANIZEWORD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Your text, in plain text or Markdown."
  }'
FieldDescription
textRequired. Plain text or Markdown. Longer than restrictions.max_chars_per_run from GET /v1/me returns 400 text_too_long; text with no prose returns 400 no_prose.
Queued responseJSON
{
  "id": "detection_01J9ABCDEF",
  "status": "queued",
  "words": 68,
  "created_at": "2026-10-13T09:30:00+00:00",
  "price_usd": "0.010000",
  "charged_usd": null,
  "result": null,
  "error": null,
  "progress": null,
  "poll_url": "/api/v1/detections/detection_01J9ABCDEF"
}

price_usd is held from your balance until the check finishes. If the available balance cannot cover it, the response is 402 insufficient_balance and nothing is queued. words counts prose only: Markdown structure and code are not charged.

Check statuses

StatusMeaning
queuedWaiting for the detector.
runningBeing read. progress shows the current stage.
succeededresult holds the report. charged_usd is the price, or 0.000000 when the text was too short to read.
failederror says why. Nothing is charged; the hold is released.
GET

/v1/detections/{id}

Returns the check. Poll poll_url about once a second until status is succeeded or failed; most checks take a few seconds, a long text up to a minute. A check is kept for one hour after it was created and then returns 404, as does a check made by another account. The text you sent is never stored.

Finished checkJSON
{
  "id": "detection_01J9ABCDEF",
  "status": "succeeded",
  "words": 68,
  "price_usd": "0.010000",
  "charged_usd": "0.010000",
  "result": {
    "version": 1,
    "score": 0.98,
    "verdict": "ai",
    "words": 68,
    "sentences": 4,
    "mean_sentence_words": 17.0,
    "paragraphs": [
      {"start": 0, "end": 286, "words": 35, "score": 0.98, "verdict": "ai"},
      {"start": 288, "end": 556, "words": 33, "score": 0.98, "verdict": "ai"}
    ],
    "signals": [
      {
        "key": "function_words",
        "label": "Function-word density",
        "value": 0.25,
        "unit": "share",
        "human": 0.5369,
        "ai": 0.4625,
        "lean": "ai",
        "human_percentile": 1.0,
        "reliability": 0.692,
        "evidence": [{"start": 0, "end": 162}, {"start": 407, "end": 556}]
      }
    ],
    "models": 3,
    "elapsed_ms": 4220
  },
  "error": null,
  "progress": null,
  "poll_url": "/api/v1/detections/detection_01J9ABCDEF"
}

The report

Every start and end is a character offset into the exact text you sent, so you can highlight paragraphs and evidence in your own copy. Keep that copy: the report holds no text.

FieldDescription
scoreHow likely the whole text is to be AI-written, from 0 to 1.
verdicthuman below 0.35, ai at 0.65 or above, mixed between. insufficient when the text has fewer than 40 words, which is not charged.
paragraphsEach paragraph's span, word count, score and verdict. A paragraph under 20 words has score and verdict null.
signalsWriting signals that separate human from AI text on our measured corpus: this text's value, the typical human and AI values, which way it leans, how reliable the signal is (0–1), and evidence spans.
modelsHow many classifiers read the text.
A reading, not proof.

Every detector, ours included, can be wrong about a given text, and other detectors will score the same text differently. Use the score as one signal, not as a verdict about who wrote something.

POST

/v1/detections/estimate

Returns what a check of this text would hold and charge now, without starting one. No API key is needed.

Estimate requestJSON
{
  "text": "Remote work has fundamentally transformed the modern workplace."
}
Estimate responseJSON
{
  "prose_word_count": 8,
  "price_usd": "0.010000"
}

Pricing

A check is paid from the same balance as runs. Its price depends only on length, so it is known before you start: currently $0.01 per check up to about 5,000 words, then $0.002 per 1,000 words. POST /v1/detections/estimate always returns the current price. You are charged only when a reading lands: a check that fails, or a text too short to read, is not charged.

Limits

LimitDetails
Rate10 checks per minute per key. A 429 includes a Retry-After header.
LengthUp to restrictions.max_chars_per_run characters (35,000 by default). At least 40 words for a verdict.
RetentionA check and its report are kept for one hour. The text is never stored.