Skip to content
Developer docs

The v1 API and the MCP server

Everything you need to call the API: how to authenticate, every endpoint with its request and response, the errors and limits, and examples in curl, JavaScript and Python.

On this page

Getting started

Overview

The API is versioned in its path, /api/v1. Every endpoint takes a POST with a JSON body and answers with JSON, errors included.

Base URL https://blurwrite.com

On the site only, not in the API: the word counter, the character counter, the plagiarism checker and the humanizer's "Take more time" run.

Rendered from the OpenAPI document, so it lists exactly the routes and fields the API accepts. The OpenAPI document

Your first call

A text needs at least 50 words.

Read "calibrated" before anything else: when it is false, the language has no fitted curve yet, so the figure must not be used as a result.

Each value is shown as its type. A real response carries the reading for your text.

Example request
curl -X POST https://blurwrite.com/api/v1/detect \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."}'
Example response
{
  "figure": "number, 0 to 100",
  "low": "number, 0 to 100",
  "high": "number, 0 to 100",
  "uncertainty": "number",
  "verdict": "human | uncertain | ai",
  "confidence": "low | medium | high",
  "sentences": [
    {
      "text": "string",
      "score": "number, 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

Send your key in the Authorization header as a bearer token. A key in the URL is refused.

A key carries scopes: detect, rewrite, summarize and grammar. A route answers 403 out_of_scope when the key does not carry its scope.

Authentication
Authorization: Bearer YOUR_API_KEY

Endpoints

POST /api/v1/detect

Read one text. The detector reading for one text: a figure from 0 to 100, the range around it, a reading per sentence and whether the language is calibrated.

Key scope: detect

Request body

FieldTypeRequiredDescription
textstringyesThe text to read or rewrite.
languagestringnoThe language code, such as "en" or "de". Left out, it is detected from the text.
contentTypestringnoWhat kind of text it is, such as "essay" or "email", when the reading should use that kind of text's curve.

Response

FieldTypeDescription
figurenumberThe reading from 0 to 100: how likely the text is machine-written. The site shows the middle of low and high on its cards and reports, which is not always this number.
lownumberThe lower end of the range around the figure.
highnumberThe upper end of the range around the figure.
uncertaintynumberHalf the width of the range, in points.
verdictstringThe band the figure falls in; a band, never a finding about who wrote the text. One of: human, uncertain, ai.
confidencestringHow much the reading can be relied on. One of: low, medium, high.
sentencesarray of SentenceScoreA reading per sentence.
wordsintegerThe words read.
languagestringThe language the text was read as.
modelstringThe model that produced the reading.
calibratedbooleanWhether the language has a fitted curve. When false, the figure must not be used as a result.
bandHumanFlagRatenumber | nullHow often human text in this band was read as machine in our measurements, or null.
usageUsageWhat this call counted.

Errors this route adds

StatusCodeMeaning
400no_textThe body has no "text".
422too_shortThe text is under the minimum length.
413text_too_longThe text is longer than the engine reads in one call. Split it. Nothing was counted.
422not_calibratedThe language cannot be read yet.
503engine_unavailableThe engine did not answer. Nothing was counted.
502engine_unavailableThe engine did not answer. Nothing was counted.
503engine_startingThe engine is starting up and was not ready in time. Nothing was counted. Try again in a minute.
503engine_busyThe engine was busy and the reading could not start in time; the site's Pro readers are served before API calls. Nothing was counted. Try again in a moment.
504engine_timeoutThe engine did not finish the text in time. Nothing was counted. Try again, or send a shorter text.
429concurrency_limitedThis key already has as many calls of this kind running as it may. Wait for one to finish, or for the time in Retry-After.
Example request
curl -X POST https://blurwrite.com/api/v1/detect \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."}'
Example response
{
  "figure": "number, 0 to 100",
  "low": "number, 0 to 100",
  "high": "number, 0 to 100",
  "uncertainty": "number",
  "verdict": "human | uncertain | ai",
  "confidence": "low | medium | high",
  "sentences": [
    {
      "text": "string",
      "score": "number, 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

Read several texts. Up to the batch limit of texts in one call. The call needs room up front for the words of every text it can read (50 words or more); the words of any text that returns no reading are given back afterwards. One text failing never fails the batch.

Key scope: detect

Request body

FieldTypeRequiredDescription
itemsarray of objectyesThe texts, each with its own "text" and an optional "id", "language" and "contentType".
items[].idstringnoYour own id for the item, returned with its result. Left out, the item's position is used.
items[].textstringyesThe text to read or rewrite.
items[].languagestringnoThe language code, such as "en" or "de". Left out, it is detected from the text.
items[].contentTypestringnoWhat kind of text it is, such as "essay" or "email", when the reading should use that kind of text's curve.

Response

FieldTypeDescription
resultsarray of BatchResultOne result per item, in the order sent.
usageUsageWhat this call counted.

Errors this route adds

StatusCodeMeaning
400batch_emptyThe body has no "items", or the list is empty.
413batch_too_largeThe batch has more items than its limit.
429concurrency_limitedThis key already has as many calls of this kind running as it may. Wait for one to finish, or for the time in Retry-After.
Example request
curl -X POST https://blurwrite.com/api/v1/detect/batch \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"id":"1","text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."},{"id":"2","text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."}]}'
Example response
{
  "results": [
    {
      "id": "string",
      "detection": {
        "figure": "number, 0 to 100",
        "low": "number, 0 to 100",
        "high": "number, 0 to 100",
        "uncertainty": "number",
        "verdict": "human | uncertain | ai",
        "confidence": "low | medium | high",
        "sentences": [
          {
            "text": "string",
            "score": "number, 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. The humanizer with its fact checks: numbers, names and quotations are kept, and a rewrite that changed a fact is repaired or reported. The mode "custom" (Pro) writes in your own style, read from a sample of your writing.

Through the API the humanizer runs its standard rewrite. "Take more time" is on the site only.

Key scope: rewrite

Request body

FieldTypeRequiredDescription
textstringyesThe text to read or rewrite.
modestringnoThe rewriting mode. One of: natural, formal, simple, academic, creative, shorten, expand, custom. Default: natural.
style_samplestringnoWith the mode "custom": a sample of your own writing, 150 to 2,000 words, read on the server. Left out, the sample saved to your account is used.
tabstringnoThe humanizer tab: the register the rewrite is written in. Standard keeps the register the text came in. One of: standard, academic, professional, casual. Default: standard.
strengthstringnoRegular keeps the content and the register. Aggressive may reorder the text and leave elaboration out, keeps every main point, and parts may read unusually. One of: regular, aggressive. Default: regular.
ownTouchstringnoA detail, example or opinion in your own words, up to 400 characters, worked into the rewrite.
languagestringnoThe language code, such as "en" or "de". Left out, it is detected from the text.

Response

FieldTypeDescription
textstringThe rewritten text.
beforeDetectionThe detector reading of your text, or null when there is none.
afterDetectionThe detector reading of the rewrite, or null.
passesintegerHow many rewrites were written before this one was chosen.
factsobjectWhat the fact checks found, and why a rewrite is not clean when it is not.
latebooleanTrue when the rewrite came back at its time limit with its checks unfinished.
usageUsageWhat this call counted.

Errors this route adds

StatusCodeMeaning
400no_textThe body has no "text".
422too_shortThe text is under the minimum length.
400unknown_modeThe mode is not one this route offers.
400unknown_optionThe tab or the strength is not one this route offers.
402plan_requiredThe mode, the tab, the strength or the own touch needs a plan the account does not have; the mode "custom" needs Pro. Nothing was counted.
400no_sampleThe mode "custom" needs a writing sample, sent or saved to the account.
400sample_too_shortThe writing sample is under the minimum length.
400sample_too_longThe writing sample is over the maximum length.
429concurrency_limitedThis key already has as many calls of this kind running as it may. Wait for one to finish, or for the time in Retry-After.
422no_rewriteThe engine answered, but no draft passed the checks (empty, a refusal or a copy of the text). Nothing was counted.
503timeoutThe rewrite took too long and was stopped. Nothing was counted.
503engine_unavailableThe engine did not answer. Nothing was counted.
502engine_unavailableThe engine did not answer. Nothing was counted.
Example request
curl -X POST https://blurwrite.com/api/v1/humanize \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."}'
Example response
{
  "text": "string",
  "before": {
    "figure": "number, 0 to 100",
    "low": "number, 0 to 100",
    "high": "number, 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number, 0 to 1",
        "verdict": "human | uncertain | ai"
      }
    ],
    "words": "integer",
    "language": "string",
    "model": "string",
    "calibrated": "boolean",
    "bandHumanFlagRate": "number | null"
  },
  "after": {
    "figure": "number, 0 to 100",
    "low": "number, 0 to 100",
    "high": "number, 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number, 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. The paraphraser, with the same mode list as the paraphrasing tool.

Key scope: rewrite

Request body

FieldTypeRequiredDescription
textstringyesThe text to read or rewrite.
modestringnoThe rewriting mode. One of: standard, fluency, formal, academic, simple, creative, expand, shorten. Default: standard.
strengthstringnoHow far the rewrite may move from the original. One of: readable, balanced, strong. Default: balanced.
readabilitystringnoThe register to write in. One of: casual, professional, academic, creative. Default: professional.
purposestringnoWhat the text is for. One of: general, essay, article, email, marketing, report, story. Default: general.
synonymsstringnoHow freely words may be replaced. One of: few, some, many. Default: some.
freezeWordsarray of stringnoWords and phrases that must come back exactly as written: at most 25, each up to 60 characters. Their words count toward the call's words.
customInstructionstringnoA short instruction of your own for the rewrite, up to 500 characters. Its words count toward the call's words.
languagestringnoThe language code, such as "en" or "de". Left out, it is detected from the text.
closedLoopbooleannoSet false to skip the closed loop. Default: true.

Response

FieldTypeDescription
textstringThe rewritten text.
beforeDetectionThe detector reading of your text, or null when there is none.
afterDetectionThe detector reading of the rewrite, or null.
passesintegerHow many rewrites were written before this one was chosen.
factsobjectWhat the fact checks found, and why a rewrite is not clean when it is not.
latebooleanTrue when the rewrite came back at its time limit with its checks unfinished.
usageUsageWhat this call counted.

Errors this route adds

StatusCodeMeaning
400no_textThe body has no "text".
422too_shortThe text is under the minimum length.
400unknown_modeThe mode is not one this route offers.
400option_invalidfreezeWords is not a list of words or phrases. Nothing was counted.
400option_too_longfreezeWords or customInstruction is over its limit. Nothing was counted.
429concurrency_limitedThis key already has as many calls of this kind running as it may. Wait for one to finish, or for the time in Retry-After.
422no_rewriteThe engine answered, but no draft passed the checks (empty, a refusal or a copy of the text). Nothing was counted.
503timeoutThe rewrite took too long and was stopped. Nothing was counted.
503engine_unavailableThe engine did not answer. Nothing was counted.
502engine_unavailableThe engine did not answer. Nothing was counted.
Example request
curl -X POST https://blurwrite.com/api/v1/paraphrase \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."}'
Example response
{
  "text": "string",
  "before": {
    "figure": "number, 0 to 100",
    "low": "number, 0 to 100",
    "high": "number, 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number, 0 to 1",
        "verdict": "human | uncertain | ai"
      }
    ],
    "words": "integer",
    "language": "string",
    "model": "string",
    "calibrated": "boolean",
    "bandHumanFlagRate": "number | null"
  },
  "after": {
    "figure": "number, 0 to 100",
    "low": "number, 0 to 100",
    "high": "number, 0 to 100",
    "uncertainty": "number",
    "verdict": "human | uncertain | ai",
    "confidence": "low | medium | high",
    "sentences": [
      {
        "text": "string",
        "score": "number, 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. The summarizer, as key sentences, a paragraph or bullets.

Key scope: summarize

Request body

FieldTypeRequiredDescription
textstringyesThe text to read or rewrite.
modestringnoThe form of the summary. One of: key-sentences, paragraph, bullets. Default: key-sentences.
lengthstringnoHow long the summary is. One of: short, medium, long. Default: medium.

Response

FieldTypeDescription
textstringThe summary.
usageUsageWhat this call counted.

Errors this route adds

StatusCodeMeaning
400no_textThe body has no "text".
422too_shortThe text is under the minimum length.
429concurrency_limitedThis key already has as many calls of this kind running as it may. Wait for one to finish, or for the time in Retry-After.
503timeoutThe rewrite took too long and was stopped. Nothing was counted.
503engine_unavailableThe engine did not answer. Nothing was counted.
502engine_unavailableThe engine did not answer. Nothing was counted.
Example request
curl -X POST https://blurwrite.com/api/v1/summarize \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."}'
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. Grammar, spelling, punctuation and style issues, each with its place in the text and suggested replacements.

Key scope: grammar

Request body

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

Response

FieldTypeDescription
issuesarray of GrammarIssueThe issues found, in the order they appear.
usageUsageWhat this call counted.

Errors this route adds

StatusCodeMeaning
400no_textThe body has no "text".
503engine_unavailableThe engine did not answer. Nothing was counted.
502engine_unavailableThe engine did not answer. Nothing was counted.
503engine_startingThe engine is starting up and was not ready in time. Nothing was counted. Try again in a minute.
504engine_timeoutThe engine did not finish the text in time. Nothing was counted. Try again, or send a shorter text.
Example request
curl -X POST https://blurwrite.com/api/v1/grammar \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"The committee met on Tuesday to review the plan for the new library. Members agreed that the reading room should stay open later on weekdays, and they asked the staff to prepare a budget for extra hours. The next meeting will look at the costs, the likely number of visitors and the effect on the rest of the building."}'
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

An error answers with its HTTP status and a body in this shape. Act on the code; the message says what went wrong and what to do next.

Errors every route can answer

StatusCodeMeaning
401key_in_urlThe key was sent in the URL. Send it in the Authorization header.
401no_keyNo key was sent.
401bad_keyThe key is not valid or was revoked.
403out_of_scopeThe key does not carry the scope this route needs.
429rate_limitedToo many requests for this key. Wait for the time in Retry-After.
403plan_lapsedThe account's plan no longer includes the API.
413too_largeThe request is too large.
400bad_bodyThe body is not a JSON object.
413too_many_wordsThe call has more words than one call takes. Split it. Nothing was counted.
402quota_exhaustedThe plan's API words for this billing period are used up and the top-up balance is empty. Nothing was counted.
402quota_shortThe call needs more words than the plan's API words left and the balance together. Nothing was counted.
402monthly_ceilingThe account has reached its API ceiling for this billing period, which holds whatever the balance. Nothing was counted.
503store_unavailableThe key, the account's word count or its saved writing sample could not be read just now, or this deployment has no account store. Nothing was run or counted.

A call reserves its words before it runs and gives them back if it fails. If the word count cannot be written at that moment, the words stay charged: a failed call then says so and carries "recorded": false in its usage, a batch answers with "recorded": false in its usage, and the words are not guessed.

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

Every figure here is the one the API enforces.

  • Each key makes at most 60 requests every 60 seconds.
  • Each key has at most 4 detect calls (a batch counts as one) and 2 humanize, paraphrase or summarize calls running at once; one more is answered 429 concurrency_limited with a Retry-After.
  • When the engines are busy, readings from the site's Pro accounts are served before API calls, so an API call may wait its turn.
  • A batch holds at most 50 texts.
  • One call takes at most 20,000 words, a single text or a whole batch.
  • The detector reads one text of up to 90,000 characters, about 10,000 words, on every plan. A longer text is answered 413 text_too_long, even inside the call's word limit.
  • An account holds up to 5 active keys, so a key can be rotated without downtime.

Response objects

The objects the endpoints return, field by field.

Detection

FieldTypeDescription
figurenumberThe reading from 0 to 100: how likely the text is machine-written. The site shows the middle of low and high on its cards and reports, which is not always this number.
lownumberThe lower end of the range around the figure.
highnumberThe upper end of the range around the figure.
uncertaintynumberHalf the width of the range, in points.
verdictstringThe band the figure falls in; a band, never a finding about who wrote the text. One of: human, uncertain, ai.
confidencestringHow much the reading can be relied on. One of: low, medium, high.
sentencesarray of SentenceScoreA reading per sentence.
wordsintegerThe words read.
languagestringThe language the text was read as.
modelstringThe model that produced the reading.
calibratedbooleanWhether the language has a fitted curve. When false, the figure must not be used as a result.
bandHumanFlagRatenumber | nullHow often human text in this band was read as machine in our measurements, or null.

SentenceScore

FieldTypeDescription
textstringThe sentence.
scorenumberFrom 0 to 1, how likely the sentence is machine-written.
verdictstringThe band the sentence falls in. One of: human, uncertain, ai.

Usage

FieldTypeDescription
recordedbooleanTrue when the count was written. False only when a batch could not give back its unread words; then only "words" is present.
wordsintegerThe words this call counted.
sourcestringWhere they came from: the plan's API words, the top-up balance, or both. One of: plan, balance, plan_and_balance.
fromPlanintegerThe words taken from the plan's API words. Present when recorded is true.
fromBalanceintegerThe words taken from the top-up balance. Present when recorded is true.
allowanceLeftinteger | nullThe plan's words left for this tool after this call, in the current billing period. Null for a tool with no pool on this plan. Present when recorded is true.
balanceintegerThe top-up balance left after this call. Present when recorded is true.

RewriteResult

FieldTypeDescription
textstringThe rewritten text.
beforeDetectionThe detector reading of your text, or null when there is none.
afterDetectionThe detector reading of the rewrite, or null.
passesintegerHow many rewrites were written before this one was chosen.
factsobjectWhat the fact checks found, and why a rewrite is not clean when it is not.
latebooleanTrue when the rewrite came back at its time limit with its checks unfinished.

GrammarIssue

FieldTypeDescription
offsetintegerWhere the issue starts in the text you sent, in UTF-16 code units (a JavaScript string index).
lengthintegerHow many UTF-16 code units of the text you sent it covers.
messagestringWhat is wrong.
shortMessagestringThe same, in a few words.
categorystringThe kind of issue. One of: grammar, spelling, punctuation, style, typography.
replacementsarray of stringSuggested replacements, best first.
contextstringThe text around the issue.

BatchResult

FieldTypeDescription
idstringThe item's id.
detectionDetectionThe reading, when the item returned one.
errorobjectWhy the item returned no reading.

Error

FieldTypeDescription
errorobject
usageUsageWhat this call counted.
MCP server

The MCP server

An agent can call the same tools through the Model Context Protocol. The server is a client of this API and nothing else, so an agent gets exactly the reading the site gives.

  • detect_textReads one text.
  • detect_batchReads several texts.
  • humanize_textHumanizes a text with its fact checks.
  • paraphrase_textParaphrases a text.
  • summarize_textSummarizes a text.
  • check_grammarChecks grammar and spelling.

Claude Code Connects online

  1. Keep your API key in an environment variable called BLURWRITE_API_KEY, where the client runs:

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

    claude mcp add --transport http blurwrite https://blurwrite.com/api/mcp --header "Authorization: Bearer $BLURWRITE_API_KEY"
  3. Or put this in .mcp.json instead:

    .mcp.json
    {
      "mcpServers": {
        "blurwrite": {
          "type": "http",
          "url": "https://blurwrite.com/api/mcp",
          "headers": {
            "Authorization": "Bearer ${BLURWRITE_API_KEY}"
          }
        }
      }
    }
  4. Check that it works: ask your assistant "Check this paragraph with Blurwrite and tell me the range and the confidence rating."

Your API key is on your dashboard under API. Never put a key in a shared file or a repository.

Every reading an agent gets carries the figure, the uncertainty around it and the calibration state, so the agent can say what the reading means and when it must not be used.

Your key

Sign in, then create a key on your dashboard.

Get your key in the dashboard

Keys are never created on this page.

What the API and the MCP server do