BYTETOOLS

LanguageTool API

Free grammar and spell checking API with no key: detect spelling, grammar and style errors in 25+ languages with suggested corrections. Tested GET and POST.

No API key requiredCORS enabledHTTPSFree tier

Endpoint tested and returned HTTP 200 on 2026-08-19

What is the LanguageTool API?

LanguageTool is a free, key-free grammar and spell checking API supporting more than 25 languages. It returns detected errors with their position, rule category and suggested replacements.

LanguageTool is the open-source engine behind a great many writing assistants, and its public API is usable without a key. Send text and a language code, and get back structured matches with character offsets and suggested corrections.

The check endpoint is a POST with form-encoded parameters, not JSON — a detail that catches people out. Each match includes an `offset` and `length` into the original string, which is what lets you highlight errors in place rather than just listing them.

Quick facts

Base URL
https://api.languagetool.org/v2
Authentication
The public API needs no key at a limited rate. Paid plans and self-hosting remove the limits.
Rate limit
About 20 requests per minute and 75KB of text per minute per IP on the free public API.
Pricing
Free public tier; paid plans and free self-hosting available.
CORS
Enabled — callable directly from browser JavaScript
Official docs
Read the docs

How to use the LanguageTool API

Every request below was executed against the live API on 2026-08-19, and the response shown is the real body it returned — not an illustration.

1. List supported languages

GET https://api.languagetool.org/v2/languages

curl
curl 'https://api.languagetool.org/v2/languages'
JavaScript (fetch)
const res = await fetch("https://api.languagetool.org/v2/languages");
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

res = requests.get("https://api.languagetool.org/v2/languages", timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
[
  {
    "name": "Arabic",
    "code": "ar",
    "longCode": "ar"
  },
  {
    "name": "Asturian",
    "code": "ast",
    "longCode": "ast-ES"
  },
  {
    "name": "Belarusian",
    "code": "be",
    "longCode": "be-BY"
  },
  {
    "name": "Breton",
    "code": "br",
    "longCode": "br-FR"
  },
  {
    "name": "Catalan",
    "code": "ca",
    "longCode": "ca-ES"
  },
  {
    "name": "Catalan (Valencian)",
    "code": "ca",
    "longCode": "ca-ES-valencia"
  },
  {
    "name": "Catalan (Balearic)",
    "code": "ca",
    "longCode": "ca-ES-balear"
  },
  {
    "name": "Danish",
    "code": "da",
    "longCode": "da-DK"
  },
  {
    "name": "German",
    "code": "de",
    "longCode": "de"
  },
  {
    "name": "German (Germany)",
    "code": "de",
    "longCode": "de-DE"
  },
  {
    "name": "German (Austria)",
    "code": "de",
    "longCode": "de-AT"
  },
  {
    "name": "German (Swiss)",
    "code": "de",
    "longCode": "de-CH"
  },
  {
    "name": "Simple German",
    "code": "de-DE-x-simple-language",
    "longCode": "de-DE-x-simple-language"
  },
  {
    "name": "Greek",
    "code": "el",
    "longCode": "el-GR"
  },
  {
    "name": "English",
    "code": "en",
    "longCode": "en"
  },
  {
    "name": "English (US)",
    "code": "en",
    "longCode": "en-US"
  },
  {
    "name": "English (GB)",
    "code": "en",
    "longCode": "en-GB"
  },
  {
    "name": "English (Australian)",
    "code": "en",
    "longCode": "en-AU"
  },
  {
    "name": "English (Canadian)",
    "code": "en",
    "longCode": "en-CA"
  },
  {
    "name": "English (New Zealand)",
    "code": "en",

2. Check text for grammar errors with a POST request

POST https://api.languagetool.org/v2/check

curl
curl -X POST 'https://api.languagetool.org/v2/check' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'text=This%20are%20a%20test&language=en-US'
JavaScript (fetch)
const res = await fetch("https://api.languagetool.org/v2/check", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: JSON.stringify(text=This%20are%20a%20test&language=en-US),
});
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

headers = {
    "Content-Type": "application/x-www-form-urlencoded",
}

payload = text=This%20are%20a%20test&language=en-US

res = requests.post("https://api.languagetool.org/v2/check", headers=headers, json=payload, timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
{
  "software": {
    "name": "LanguageTool",
    "version": "6.9-SNAPSHOT",
    "buildDate": "2026-08-19 17:50:03 +0000",
    "apiVersion": 1,
    "premium": true,
    "premiumHint": "You might be missing errors only the Premium version can find. Contact us at support<at>languagetoolplus.com.",
    "status": ""
  },
  "warnings": {
    "incompleteResults": false
  },
  "language": {
    "name": "English (US)",
    "code": "en-US",
    "detectedLanguage": {
      "name": "English (US)",
      "code": "en-US",
      "confidence": 0.99977934,
      "source": "ngram"
    }
  },
  "matches": [
    {
      "message": "The singular demonstrative pronoun ‘this’ does not agree with the plural verb ‘are’. Did you mean “these”?",
      "shortMessage": "Grammatical problem: use ‘these’",
      "replacements": [
        {
          "value": "These"
        }
      ],
      "offset": 0,
      "length": 4,
      "context": {
        "text": "This are a test",
        "offset": 0,
        "length": 4
      },
      "sentence": "This are a test",
      "type": {
        "typeName": "Other"
      },
      "rule": {
        "id": "THIS_NNS",
        "subId": "5",
        "sourceFile": "grammar.xml",
        "description": "'this' vs. 'these'",
        "issueType": "grammar",
        "category": {
          "id": "GRAMMAR",
          "name": "Grammar"
        },
        "isPremium": false,
        "confidence": 0.64
      },
      "ignoreForIncompleteSentence": false,
      "contextForSureMatch": 1
    },
    {
      "message": "The verb ‘are’ is plural. Did you mean: “is”? Did you use a verb

Parameters

ParameterTypeRequiredDescription
textstringRequiredThe text to check, on the POST /check endpoint. This are a test
languagestringRequiredLanguage code, or `auto` to detect. en-US
enabledOnlybooleanOptionalOnly run explicitly enabled rules. false
disabledRulesstringOptionalComma-separated rule ids to skip. WHITESPACE_RULE

Response fields

(languages) name / code / longCodestring
Supported language names and codes.
matches[].messagestring
Human-readable explanation of the problem.
matches[].offset / lengthinteger
Character position and span of the error in your text.
matches[].replacementsarray
Suggested corrections, best first.
matches[].rule.categoryobject
Error category such as Grammar or Typos.
softwareobject
Engine name and version.

What you can build with the LanguageTool API

  • Add grammar and spell checking to a text editor or CMS
  • Validate user-generated content before publishing
  • Build a writing assistant with inline error highlighting
  • Check multilingual content with one API

Common errors and how to fix them

400 on the check endpoint

Parameters must be form-encoded, not JSON.

Fix: POST with Content-Type: application/x-www-form-urlencoded and text=...&language=...

429

Free tier limit exceeded.

Fix: Around 20 requests per minute and 75KB per minute. Batch text into fewer, larger requests, or self-host.

Offsets misaligned

Offsets are character positions in the original text.

Fix: Apply replacements from the end backwards so earlier offsets stay valid.

LanguageTool API — frequently asked questions

Is the LanguageTool API free?

Yes, the public API works with no key at roughly 20 requests per minute. Paid plans raise the limits, and the engine is open source so you can self-host without limits.

Why does my check request fail with a 400?

The /check endpoint expects form-encoded parameters, not a JSON body. Set Content-Type to application/x-www-form-urlencoded.

How do I apply the suggested corrections?

Each match gives an offset and length into your original text plus ranked replacements. Apply them from the end of the string backwards so earlier offsets remain valid.

How many languages are supported?

More than 25, including English variants, German, French, Spanish, Portuguese, Dutch and Russian. Request /v2/languages for the current list.

Tools that pair with this API

LanguageTool is an independent third-party service and is not affiliated with ByteTools or ByteVancer. Details on this page were verified on 2026-08-19; always check the official documentation before relying on this API in production, as terms and limits can change.