Plain Language Simplification API
The simplify endpoint rewrites a text in plain language at a reading level you choose — for plain-language compliance (e.g. agencies covered by the US Plain Writing Act), healthcare patient communications, legal notices, customer support and education. The rewrite keeps all of the text's content, structure and language: nothing is summarized, dropped or translated. To shorten a text instead, see summarize.
The improvement is verifiable: when the text's language supports readability scoring, the response includes a deterministic before/after readability block (Flesch-Kincaid grade level and reading ease, the same formulas as the statistics endpoint), so you can see — and show your users — how far the rewrite actually moved the score.
Terms that must survive the rewrite (product names, defined legal terms) can be
listed in preserve_terms; a rewrite that drops one is refused server-side rather than returned.
Sample Code
- cURL
- JavaScript
- Python
- Python (Sapling client)
curl -X POST https://api.sapling.ai/api/v1/simplify \
-H "Content-Type: application/json" \
-d '{"key":"<api-key>", "text":"The party of the first part shall remit payment within thirty (30) days of receipt of the invoice.", "reading_level": "plain", "preserve_terms": ["invoice"]}'
import axios from 'axios';
async function run(text) {
try {
const response = await axios.post(
'https://api.sapling.ai/api/v1/simplify',
{
key: '<api-key>',
text,
reading_level: 'plain',
preserve_terms: ['invoice'],
},
);
const {status, data} = response;
console.log({status});
console.log(JSON.stringify(data, null, 4));
} catch (err) {
const msg = err.response?.data?.msg || err.message;
console.log({err: msg});
}
}
run('The party of the first part shall remit payment within thirty (30) days of receipt of the invoice.');
import requests
from pprint import pprint
response = requests.post(
"https://api.sapling.ai/api/v1/simplify",
json={
"key": "<api-key>",
"text": ("The party of the first part shall remit payment within "
"thirty (30) days of receipt of the invoice."),
"reading_level": "plain",
"preserve_terms": ["invoice"],
}
)
if 200 <= response.status_code < 300:
pprint(response.json())
else:
print('Error: ', response.status_code, response.text)
from sapling import SaplingClient
api_key = '<api-key>'
client = SaplingClient(api_key=api_key)
result = client.simplify(
'The party of the first part shall remit payment within thirty (30) '
'days of receipt of the invoice.',
reading_level='plain',
preserve_terms=['invoice'],
)
print(result['simplified'])
readability = result.get('readability')
if readability:
print(f"Grade {readability['before']['grade']} -> "
f"{readability['after']['grade']}")
Sample Response
{
"simplified": "You must pay within 30 days of getting the invoice.",
"reading_level": "plain",
"lang": "en",
"readability": {
"before": {"grade": 12.3, "ease": 42.1},
"after": {"grade": 5.8, "ease": 78.4}
}
}
Request Parameters
POST to https://api.sapling.ai/api/v1/simplify
key: String
32-character API key. Can also be supplied via the Authorization header as a bearer token; if both are provided, the key parameter takes precedence.
text: String
The text to simplify, up to 5,000 characters. Sent to the model exactly as submitted — markup and
line structure are preserved, not stripped — and the rewrite gives you your document back with its
structure intact. Empty or whitespace-only text returns a 400. The text is treated as untrusted
data: instructions inside it are ignored and it is rewritten on its content alone.
reading_level: String, optional — defaults to plain
The target audience:
plain(default): plain-language style for a general audience, in the spirit of plainlanguage.gov — short sentences, everyday words, active voice.elementary: ~US grade 3–5.middle_school: ~US grade 6–8.high_school: ~US grade 9–10.
preserve_terms: List[String], optional
Up to 20 terms (each up to 100 characters) the rewrite must keep rather than paraphrase away —
product names, trademarks, defined legal terms. Enforced structurally: a rewrite that drops a term the
source contains is refused with a 502 rather than returned. Matching is case-insensitive with
whitespace collapsed, so line re-wrapping does not count as dropping a term — but by the same token a
change in casing alone (e.g. iPhone → Iphone) is not treated as a dropped term, so where the
exact capitalization of a term matters, verify it in the returned text.
lang: String, optional — defaults to auto-detection
ISO 639-1 code (e.g. en) selecting the readability formula for the before/after scores. Omit to
auto-detect (falls back to en). This never changes the rewrite itself —
the output always stays in the text's own language.
Response Parameters
simplified: String
The rewritten text: same content, same language, same document structure, at the target reading
level.
reading_level: String
The reading level that was applied.
lang: String
The language the readability scores were computed for — the value you passed, or the detected
language when omitted.
readability: Object, optional
{"before": {"grade": ..., "ease": ...}, "after": {"grade": ..., "ease": ...}} — deterministic
Flesch-Kincaid grade level and reading ease for the submitted text and the rewrite, computed over the
prose (markup excluded) with the same formulas as the statistics endpoint.
Omitted (never an error) when the language has no supported readability formula or the text has no
scoreable prose.
Errors
| Status | Meaning |
|---|---|
400 | Validation error — missing, empty or oversized text, an unknown reading_level, or invalid preserve_terms. The body is {"msg": "..."}. |
401 / 403 | Missing or invalid API key. |
429 | Rate limit exceeded or key over capacity. |
502 | {"msg": "Unexpected error simplifying text."} — the rewriting model failed or the rewrite dropped a preserved term; safe to retry. Not billed and not cached. |
Tips
- Score first, rewrite second. The statistics endpoint returns the same readability scores on their own — use it to decide which documents need simplifying, then send only those here.
- Pick the level for your audience, not the lowest one.
plainis the right default for public, legal and healthcare communications;elementarytrades more nuance away than most adult-facing content wants. - List your defined terms. In legal and healthcare text, capitalized defined terms
(
"Subscriber","the Provider") and product names should go inpreserve_termsso the rewrite can't paraphrase them away. - Check the delta.
readability.after.gradetells you whether the text landed near your target; a document dense with unavoidable technical terms may need a glossary rather than a lower reading level. - Results are cached on Sapling's side for about three days, keyed on the text, reading level and preserve terms — re-running the same document returns the same rewrite; changing any of them re-generates.