Skip to main content
Developer docs

API v1 and the MCP server

How to authenticate, each endpoint with its request and response, the errors and limits, and examples in curl, JavaScript and Python.

On this page

Getting started

Overview

The version is part of the path: /api/v1. Every endpoint accepts a POST with a JSON body and responds in JSON, including errors.

Base URL https://textlume.com

Available on the site but not through the API: the word counter, the character counter, the plagiarism checker and the humanizer's "Take more time" option.

Generated from the OpenAPI document, so it shows exactly the routes and fields the API accepts. OpenAPI document

Your first request

The minimum text length is 50 words.

Check "calibrated" first. If it is false, there is no fitted curve for that language yet, and the figure must not be treated as a result.

Values are shown as their types. A real response contains the reading for your text.

Example request
curl -X POST https://textlume.com/api/v1/detect \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."}'
Example response
{
  "figure": "number from 0 to 100",
  "low": "number from 0 to 100",
  "high": "number from 0 to 100",
  "uncertainty": "number",
  "verdict": "human | uncertain | ai",
  "confidence": "low | medium | high",
  "sentences": [
    {
      "text": "string",
      "score": "number from 0 to 1",
      "verdict": "human | uncertain | ai"
    }
  ],
  "words": "integer",
  "language": "string",
  "model": "string",
  "calibrated": "boolean",
  "bandHumanFlagRate": "number | null",
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

Authentication

Pass your key as a bearer token in the Authorization header. Requests with the key in the URL are rejected.

Each key has scopes: detect, rewrite, summarize and grammar. If a key lacks the scope a route needs, the route returns 403 out_of_scope.

Authentication
Authorization: Bearer YOUR_API_KEY

Endpoints

POST /api/v1/detect

Check one text. Returns the detector reading for a single text: a figure from 0 to 100, the range around it, a reading for each sentence and whether the language is calibrated.

Required scope: detect

Request body

FieldTypeRequiredDescription
textstringyesThe text to check or rewrite.
languagestringnoA language code such as "en" or "de". If omitted, the language is identified from the text.
contentTypestringnoThe kind of text, such as "essay" or "email". Set it when the reading should use the curve for that kind of text.

Response

FieldTypeDescription
figurenumberThe reading on a scale from 0 to 100, showing how likely it is that the text was machine-written. Cards and reports on the site show the midpoint between low and high, which can differ from this value.
lownumberThe bottom of the range around the figure.
highnumberThe top of the range around the figure.
uncertaintynumberHalf the width of the range, in points.
verdictstringThe band that contains the figure. It describes the figure only and makes no statement about who wrote the text. Allowed values: human, uncertain, ai.
confidencestringHow far the reading can be trusted. Allowed values: low, medium, high.
sentencesarray of SentenceScoreA reading for each sentence.
wordsintegerThe number of words read.
languagestringThe language the text was read in.
modelstringThe model that produced this reading.
calibratedbooleanWhether a fitted curve exists for this language. If false, do not use the figure as a result.
bandHumanFlagRatenumber | nullIn our measurements, the share of human-written texts in this band that were read as machine-written. Null when not available.
usageUsageThe words this call counted.

Errors specific to this route

StatusCodeMeaning
400no_textThe request body does not contain "text".
422too_shortThe text is shorter than the minimum length.
413text_too_longThe text is longer than the engine can read in a single call. Split it into smaller parts. No words were counted.
422not_calibratedReadings are not available for this language yet.
503engine_unavailableThe engine did not respond. No words were counted.
502engine_unavailableThe engine did not respond. No words were counted.
503engine_startingThe engine was still starting and was not ready in time. No words were counted. Try again in about a minute.
503engine_busyThe engine was busy and could not start the reading in time. Pro users on the site are served ahead of API calls. No words were counted. Try again shortly.
504engine_timeoutThe engine could not finish the text in time. No words were counted. Try again, or send a shorter text.
429concurrency_limitedThis key already has the maximum number of calls of this type in flight. Wait until one finishes, or for the time given in Retry-After.
Example request
curl -X POST https://textlume.com/api/v1/detect \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."}'
Example response
{
  "figure": "number from 0 to 100",
  "low": "number from 0 to 100",
  "high": "number from 0 to 100",
  "uncertainty": "number",
  "verdict": "human | uncertain | ai",
  "confidence": "low | medium | high",
  "sentences": [
    {
      "text": "string",
      "score": "number from 0 to 1",
      "verdict": "human | uncertain | ai"
    }
  ],
  "words": "integer",
  "language": "string",
  "model": "string",
  "calibrated": "boolean",
  "bandHumanFlagRate": "number | null",
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

POST /api/v1/detect/batch

Check several texts. Send as many texts as the batch limit allows in a single call. Before it runs, the call must have enough words available for every text it could read (50 words or more per text). Words reserved for a text that returns no reading are refunded afterwards. A failure on one text does not fail the rest of the batch.

Required scope: detect

Request body

FieldTypeRequiredDescription
itemsarray of objectyesThe texts to check. Each item has its own "text" and may include an "id", a "language" and a "contentType".
items[].idstringnoAn id of your choice, returned with the item's result. If omitted, the item's position in the list is used.
items[].textstringyesThe text to check or rewrite.
items[].languagestringnoA language code such as "en" or "de". If omitted, the language is identified from the text.
items[].contentTypestringnoThe kind of text, such as "essay" or "email". Set it when the reading should use the curve for that kind of text.

Response

FieldTypeDescription
resultsarray of BatchResultOne result for each item, in the order the items were sent.
usageUsageThe words this call counted.

Errors specific to this route

StatusCodeMeaning
400batch_emptyThe request body has no "items", or the list is empty.
413batch_too_largeThe batch contains more items than the limit allows.
429concurrency_limitedThis key already has the maximum number of calls of this type in flight. Wait until one finishes, or for the time given in Retry-After.
Example request
curl -X POST https://textlume.com/api/v1/detect/batch \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"id":"1","text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."},{"id":"2","text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."}]}'
Example response
{
  "results": [
    {
      "id": "string",
      "detection": {
        "figure": "number from 0 to 100",
        "low": "number from 0 to 100",
        "high": "number from 0 to 100",
        "uncertainty": "number",
        "verdict": "human | uncertain | ai",
        "confidence": "low | medium | high",
        "sentences": [
          {
            "text": "string",
            "score": "number from 0 to 1",
            "verdict": "human | uncertain | ai"
          }
        ],
        "words": "integer",
        "language": "string",
        "model": "string",
        "calibrated": "boolean",
        "bandHumanFlagRate": "number | null"
      },
      "error": {
        "code": "string",
        "message": "string"
      }
    }
  ],
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

POST /api/v1/humanize

Humanize a text. Runs the humanizer with its fact checks. Numbers, names and quotations are preserved, and if a rewrite changes a fact, it is repaired or flagged. The "custom" mode (Pro) writes in your own style, learned from a sample of your writing.

The API runs the humanizer's standard rewrite. The "Take more time" option exists only on the site.

Required scope: rewrite

Request body

FieldTypeRequiredDescription
textstringyesThe text to check or rewrite.
modestringnoThe rewrite mode. Allowed values: natural, formal, simple, academic, creative, shorten, expand, custom. Defaults to natural.
style_samplestringnoUsed with the "custom" mode: a sample of your own writing between 150 and 2,000 words, processed on the server. If omitted, the sample saved to your account is used.
tabstringnoThe humanizer tab sets the tone the rewrite is written in. Standard keeps the tone of the original text. Allowed values: standard, academic, professional, casual. Defaults to standard.
strengthstringnoRegular keeps the content and tone. Aggressive may reorder sentences and drop extra detail while keeping every main point, so some parts may read a little unusual. Allowed values: regular, aggressive. Defaults to regular.
ownTouchstringnoA detail, example or opinion in your own words, up to 400 characters, that gets worked into the rewrite.
languagestringnoA language code such as "en" or "de". If omitted, the language is identified from the text.

Response

FieldTypeDescription
textstringThe rewritten text.
beforeDetectionThe detector reading of the text you sent, or null if there is none.
afterDetectionThe detector reading of the rewritten text, or null.
passesintegerThe number of rewrites produced before this one was selected.
factsobjectThe fact check findings, including the reason when a rewrite is not clean.
latebooleanTrue when the rewrite was returned at its time limit before its checks had finished.
usageUsageThe words this call counted.

Errors specific to this route

StatusCodeMeaning
400no_textThe request body does not contain "text".
422too_shortThe text is shorter than the minimum length.
400unknown_modeThis route does not offer the requested mode.
400unknown_optionThis route doesn't offer that tab or strength.
402plan_requiredThe mode, tab, strength or personal touch you chose needs a plan this account does not have. The "custom" mode requires Pro. No words were counted.
400no_sampleThe "custom" mode needs a writing sample, either sent with the request or saved to the account.
400sample_too_shortThe writing sample is shorter than the minimum length.
400sample_too_longThe writing sample is longer than the maximum length.
429concurrency_limitedThis key already has the maximum number of calls of this type in flight. Wait until one finishes, or for the time given in Retry-After.
422no_rewriteThe engine responded, but none of its drafts passed the checks (empty output, a refusal or a copy of the input). No words were counted.
503timeoutThe rewrite ran too long and was stopped. No words were counted.
503engine_unavailableThe engine did not respond. No words were counted.
502engine_unavailableThe engine did not respond. No words were counted.
Example request
curl -X POST https://textlume.com/api/v1/humanize \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."}'
Example response
{
  "text": "string",
  "before": {
    "figure": "number from 0 to 100",
    "low": "number from 0 to 100",
    "high": "number from 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number from 0 to 1",
        "verdict": "human | uncertain | ai"
      }
    ],
    "words": "integer",
    "language": "string",
    "model": "string",
    "calibrated": "boolean",
    "bandHumanFlagRate": "number | null"
  },
  "after": {
    "figure": "number from 0 to 100",
    "low": "number from 0 to 100",
    "high": "number from 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number from 0 to 1",
        "verdict": "human | uncertain | ai"
      }
    ],
    "words": "integer",
    "language": "string",
    "model": "string",
    "calibrated": "boolean",
    "bandHumanFlagRate": "number | null"
  },
  "passes": "integer",
  "facts": "object",
  "late": "boolean",
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

POST /api/v1/paraphrase

Paraphrase a text. Runs the paraphraser, with the same modes as the paraphrasing tool on the site.

Required scope: rewrite

Request body

FieldTypeRequiredDescription
textstringyesThe text to check or rewrite.
modestringnoThe rewrite mode. Allowed values: standard, fluency, formal, academic, simple, creative, expand, shorten. Defaults to standard.
strengthstringnoHow far the rewrite may depart from the original. Allowed values: readable, balanced, strong. Defaults to balanced.
readabilitystringnoThe reading level to write for. Allowed values: casual, professional, academic, creative. Defaults to professional.
purposestringnoThe purpose of the text. Allowed values: general, essay, article, email, marketing, report, story. Defaults to general.
synonymsstringnoHow freely words may be swapped for synonyms. Allowed values: few, some, many. Defaults to some.
freezeWordsarray of stringnoWords and phrases that must be returned exactly as written. Up to 25 entries, each no longer than 60 characters. Their words count toward the call's word total.
customInstructionstringnoYour own short instruction for the rewrite, no longer than 500 characters. Its words count toward the call's word total.
languagestringnoA language code such as "en" or "de". If omitted, the language is identified from the text.
closedLoopbooleannoSet to false to turn off the closed loop. Defaults to true.

Response

FieldTypeDescription
textstringThe rewritten text.
beforeDetectionThe detector reading of the text you sent, or null if there is none.
afterDetectionThe detector reading of the rewritten text, or null.
passesintegerThe number of rewrites produced before this one was selected.
factsobjectThe fact check findings, including the reason when a rewrite is not clean.
latebooleanTrue when the rewrite was returned at its time limit before its checks had finished.
usageUsageThe words this call counted.

Errors specific to this route

StatusCodeMeaning
400no_textThe request body does not contain "text".
422too_shortThe text is shorter than the minimum length.
400unknown_modeThis route does not offer the requested mode.
400option_invalidfreezeWords must be a list of words or phrases. Nothing was counted.
400option_too_longfreezeWords or customInstruction is over its length limit. Nothing was counted.
429concurrency_limitedThis key already has the maximum number of calls of this type in flight. Wait until one finishes, or for the time given in Retry-After.
422no_rewriteThe engine responded, but none of its drafts passed the checks (empty output, a refusal or a copy of the input). No words were counted.
503timeoutThe rewrite ran too long and was stopped. No words were counted.
503engine_unavailableThe engine did not respond. No words were counted.
502engine_unavailableThe engine did not respond. No words were counted.
Example request
curl -X POST https://textlume.com/api/v1/paraphrase \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."}'
Example response
{
  "text": "string",
  "before": {
    "figure": "number from 0 to 100",
    "low": "number from 0 to 100",
    "high": "number from 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number from 0 to 1",
        "verdict": "human | uncertain | ai"
      }
    ],
    "words": "integer",
    "language": "string",
    "model": "string",
    "calibrated": "boolean",
    "bandHumanFlagRate": "number | null"
  },
  "after": {
    "figure": "number from 0 to 100",
    "low": "number from 0 to 100",
    "high": "number from 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number from 0 to 1",
        "verdict": "human | uncertain | ai"
      }
    ],
    "words": "integer",
    "language": "string",
    "model": "string",
    "calibrated": "boolean",
    "bandHumanFlagRate": "number | null"
  },
  "passes": "integer",
  "facts": "object",
  "late": "boolean",
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

POST /api/v1/summarize

Summarize a text. Runs the summarizer and returns key sentences, a paragraph or bullet points.

Required scope: summarize

Request body

FieldTypeRequiredDescription
textstringyesThe text to check or rewrite.
modestringnoThe format of the summary. Allowed values: key-sentences, paragraph, bullets. Defaults to key-sentences.
lengthstringnoThe length of the summary. Allowed values: short, medium, long. Defaults to medium.

Response

FieldTypeDescription
textstringThe summary text.
usageUsageThe words this call counted.

Errors specific to this route

StatusCodeMeaning
400no_textThe request body does not contain "text".
422too_shortThe text is shorter than the minimum length.
429concurrency_limitedThis key already has the maximum number of calls of this type in flight. Wait until one finishes, or for the time given in Retry-After.
503timeoutThe rewrite ran too long and was stopped. No words were counted.
503engine_unavailableThe engine did not respond. No words were counted.
502engine_unavailableThe engine did not respond. No words were counted.
Example request
curl -X POST https://textlume.com/api/v1/summarize \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."}'
Example response
{
  "text": "string",
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

POST /api/v1/grammar

Check grammar. Finds grammar, spelling, punctuation and style issues and returns each one with its position in the text and suggested replacements.

Required scope: grammar

Request body

FieldTypeRequiredDescription
textstringyesThe text to check or rewrite.
languagestringnoThe language code for the check, such as "en-US" or "de-DE". Defaults to en-US.

Response

FieldTypeDescription
issuesarray of GrammarIssueThe issues found, in the order they occur in the text.
usageUsageThe words this call counted.

Errors specific to this route

StatusCodeMeaning
400no_textThe request body does not contain "text".
503engine_unavailableThe engine did not respond. No words were counted.
502engine_unavailableThe engine did not respond. No words were counted.
503engine_startingThe engine was still starting and was not ready in time. No words were counted. Try again in about a minute.
504engine_timeoutThe engine could not finish the text in time. No words were counted. Try again, or send a shorter text.
Example request
curl -X POST https://textlume.com/api/v1/grammar \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"On Tuesday evening the neighborhood association met to discuss the proposed bike lane on Elm Street. Several shop owners worried about losing parking spaces, while parents said the lane would make the route to school safer. The group asked the city to share traffic counts before the next meeting and agreed to collect comments from residents over the coming weeks."}'
Example response
{
  "issues": [
    {
      "offset": "integer",
      "length": "integer",
      "message": "string",
      "shortMessage": "string",
      "category": "grammar | spelling | punctuation | style | typography",
      "replacements": [
        "string"
      ],
      "context": "string"
    }
  ],
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

Reference

Errors

Errors come with an HTTP status and a body in the shape below. Handle errors by their code. The message explains what failed and what to do about it.

Errors any route can return

StatusCodeMeaning
401key_in_urlThe key was included in the URL. Send it in the Authorization header instead.
401no_keyThe request did not include a key.
401bad_keyThe key is invalid or has been revoked.
403out_of_scopeThe key lacks the scope this route requires.
429rate_limitedThis key has sent too many requests. Wait for the time given in Retry-After.
403plan_lapsedThe account's current plan does not include API access.
413too_largeThe request body is too large.
400bad_bodyThe request body is not a JSON object.
413too_many_wordsThis call has more words than a single call accepts. Split it up. Nothing was counted.
402quota_exhaustedThe plan's API words for this billing period are used up, and there is no top-up balance left. No words were counted.
402quota_shortThe call needs more words than the plan's remaining API words and the top-up balance can cover together. No words were counted.
402monthly_ceilingThe account has hit its API ceiling for this billing period. The ceiling applies regardless of the top-up balance. No words were counted.
503store_unavailableThe key, the account's word count or its saved writing sample could not be read at the moment, or this deployment has no account store. Nothing was run and no words were counted.

Each call reserves its words before it runs and returns them if it fails. If the word count can't be saved at that moment, the words stay charged. A failed call says so and shows "recorded": false in its usage, a batch shows "recorded": false in its usage, and we never estimate the words.

Error body
{
  "error": {
    "code": "string",
    "message": "string",
    "docs": "string",
    "available": "integer"
  },
  "usage": {
    "recorded": "boolean",
    "words": "integer",
    "source": "plan | balance | plan_and_balance",
    "fromPlan": "integer",
    "fromBalance": "integer",
    "allowanceLeft": "integer | null",
    "balance": "integer"
  }
}

Limits

These are the exact values the API enforces.

  • A key can send up to 60 requests in each window of 60 seconds.
  • Each key can have up to 4 detect calls (one batch counts as one call) and up to 2 humanize, paraphrase or summarize calls in flight at the same time. Any call beyond that gets 429 concurrency_limited with a Retry-After header.
  • When the engines are under load, Pro users on the site are served ahead of API calls, so an API call may have to wait.
  • Maximum texts per batch: 50.
  • Each call accepts up to 20,000 words, whether you send one text or a whole batch.
  • On every plan, the detector reads a single text of up to 90,000 characters, which is roughly 10,000 words. Longer texts get a 413 text_too_long response, even when the call is within its word limit.
  • An account can hold up to 5 active keys at once, so you can rotate a key without downtime.

Response objects

Every object the endpoints return, with each of its fields.

Detection

FieldTypeDescription
figurenumberThe reading on a scale from 0 to 100, showing how likely it is that the text was machine-written. Cards and reports on the site show the midpoint between low and high, which can differ from this value.
lownumberThe bottom of the range around the figure.
highnumberThe top of the range around the figure.
uncertaintynumberHalf the width of the range, in points.
verdictstringThe band that contains the figure. It describes the figure only and makes no statement about who wrote the text. Allowed values: human, uncertain, ai.
confidencestringHow far the reading can be trusted. Allowed values: low, medium, high.
sentencesarray of SentenceScoreA reading for each sentence.
wordsintegerThe number of words read.
languagestringThe language the text was read in.
modelstringThe model that produced this reading.
calibratedbooleanWhether a fitted curve exists for this language. If false, do not use the figure as a result.
bandHumanFlagRatenumber | nullIn our measurements, the share of human-written texts in this band that were read as machine-written. Null when not available.

SentenceScore

FieldTypeDescription
textstringThe sentence.
scorenumberA value from 0 to 1 for how likely it is that the sentence was machine-written.
verdictstringThe band that contains the sentence score. Allowed values: human, uncertain, ai.

Usage

FieldTypeDescription
recordedbooleanTrue when the word count was saved. False only when a batch could not refund the words of texts it did not read. In that case only "words" is included.
wordsintegerThe number of words this call counted.
sourcestringWhere the words were taken from: the plan's API words, the top-up balance or both. Allowed values: plan, balance, plan_and_balance.
fromPlanintegerWords taken from the plan's API words. Included when recorded is true.
fromBalanceintegerWords taken from the top-up balance. Included when recorded is true.
allowanceLeftinteger | nullThe plan's remaining words for this tool in the current billing period, after this call. Null when the plan has no word pool for the tool. Included when recorded is true.
balanceintegerThe top-up balance remaining after this call. Included when recorded is true.

RewriteResult

FieldTypeDescription
textstringThe rewritten text.
beforeDetectionThe detector reading of the text you sent, or null if there is none.
afterDetectionThe detector reading of the rewritten text, or null.
passesintegerThe number of rewrites produced before this one was selected.
factsobjectThe fact check findings, including the reason when a rewrite is not clean.
latebooleanTrue when the rewrite was returned at its time limit before its checks had finished.

GrammarIssue

FieldTypeDescription
offsetintegerThe start of the issue in the text you sent, in UTF-16 code units (the same as a JavaScript string index).
lengthintegerThe number of UTF-16 code units of your text that the issue spans.
messagestringA description of the problem.
shortMessagestringA short version of the message.
categorystringThe type of issue. Allowed values: grammar, spelling, punctuation, style, typography.
replacementsarray of stringSuggested replacements, with the best one first.
contextstringThe text surrounding the issue.

BatchResult

FieldTypeDescription
idstringThe id of the item.
detectionDetectionThe reading, if the item returned one.
errorobjectThe reason the item returned no reading.

Error

FieldTypeDescription
errorobject
usageUsageThe words this call counted.
MCP server

MCP server

Agents can use the same tools through the Model Context Protocol. The server talks only to this API, so an agent receives the same reading as the site.

  • detect_textChecks one text.
  • detect_batchChecks several texts.
  • humanize_textHumanizes a text and runs the fact checks.
  • paraphrase_textParaphrases a text.
  • summarize_textSummarizes a text.
  • check_grammarChecks grammar and spelling.

Claude Code Connects to the hosted server

  1. Store your API key in an environment variable named TEXTLUME_API_KEY on the machine where the client runs:

    export TEXTLUME_API_KEY="YOUR_API_KEY"
  2. Run this command in a terminal:

    claude mcp add --transport http textlume https://textlume.com/api/mcp --header "Authorization: Bearer $TEXTLUME_API_KEY"
  3. Or add it to .mcp.json instead:

    .mcp.json
    {
      "mcpServers": {
        "textlume": {
          "type": "http",
          "url": "https://textlume.com/api/mcp",
          "headers": {
            "Authorization": "Bearer ${TEXTLUME_API_KEY}"
          }
        }
      }
    }
  4. To test the connection, ask your assistant: "Use Textlume to check this paragraph and give me the range and the confidence rating."

You will find your API key on your dashboard, under API. Keep keys out of shared files and repositories.

Each reading an agent receives includes the figure, its uncertainty and the calibration state. That lets the agent explain what the reading means and when it should not be used.

API key

Sign in first, then create a key on your dashboard.

Get a key on the dashboard

This page does not create keys.

Overview of the API and the MCP server