API guide and examples
Use Unslop from a script or another application. This guide describes version 1.3.0. The generated OpenAPI reference lists every accepted field; the API explorer lets you try requests in the browser.
You can create an account and get an API key immediately. Save the key and recovery code when shown. The workbench also accepts your signed-in browser session. Documentation is public. Agents can register over HTTP. Prepaid requests use a human-funded balance, spending caps and idempotency headers; see pricing.
Your account and API key
Sign up with a username and password. Save the API key and recovery code when shown. You can use the workbench immediately, or send the key in the Authorization: Bearer header from your application.
Free accounts have daily word, request, and AI-call limits. The signup page lists the current allowances, and GET /v1/usage reports yours. AI calls also share a service-wide daily allowance. Retrying a rewrite or adding meaning review uses more calls. Daily limits reset at midnight UTC; request-per-minute limits reset at the next UTC minute.
You can replace or revoke your key on the account page. A new key immediately replaces the old one, so update any scripts that use it. Rotating a key doesn't reset usage or remove profiles. Save your recovery code: there is no email password reset.
Make your first request
The base URL is https://unslopapi.vercel.app. Send JSON with Content-Type: application/json and your key in the Authorization: Bearer header. Keep keys in your server or local environment, not in public website code.
Save the analysis example below as analysis.json. Set UNSLOP_KEY in your environment, then run:
curl --fail-with-body https://unslopapi.vercel.app/v1/analyze \
-H "Authorization: Bearer $UNSLOP_KEY" \
-H 'Content-Type: application/json' \
--data-binary @analysis.json
This request runs deterministic analysis and makes no AI calls. A rewrite that passes its gate and starts generation sends the original text and guidance to external AI services. Each model attempt consumes one account AI call. Skipped rewrites still count as requests and consume the submitted-word allowance.
Copyable request examples
These are request bodies, not recorded responses or promises about a model's output. Save the one you need to a JSON file and use the matching endpoint in the command above.
Analyze a draft without AI
POST /v1/analyze. The ceiling asks whether the estimated grade is at most 8; easier text passes.
{
"text": "It's worth noting that we fixed the search page. Your saved filters now work again. You can open the page, choose a filter, and see the matching notes without setting it up again.",
"genre": "technical",
"allow_ai": false,
"include": ["score", "quality", "explain", "inspect"],
"constraints": { "readability_ceiling": 8 }
}
Edit a complete draft
Rewrites replace common count-led headings and paired-count slogans with descriptive wording. The count_framing_frequency check permits at most min(floor(original_occurrences × 0.05), floor(output_words / 2000)) matches, with at least 2,000 words between retained matches. Short drafts permit none. Detection is heuristic; factual quantities in prose, dates, versions, list numbering and protected content are not targets. Required numbers must be preserved, not deleted to satisfy style. A failed check enters the correction attempt; if it still fails, the original returns without a charge.
POST /v1/rewrite defaults to mode: "document". One call edits the entire draft, then a separate review checks factual meaning. Mechanical constraints protect numbers, quotations and protected content. One correction attempt is allowed after a failed check. If no candidate passes, the original is returned with no customer charge.
Choose model_level: low, medium, high or max. Medium is the default. Model identities remain private. The style gate is disabled by default; set rewrite_gate.enabled: true to use its score and word-count thresholds. A configured gate skip costs nothing.
{
"text": "It's worth noting that we fixed the search page. Your saved filters now work again. You can open the page, choose a filter, and see the matching notes without setting it up again.",
"mode": "document",
"allow_ai": true,
"semantic_review": true,
"retry_on_failure": true,
"genre": "technical",
"instructions": "Keep the facts. Remove unnecessary introductions. Keep the term saved filters.",
"constraints": {
"max_change_ratio": 1.5,
"readability_ceiling": 8,
"protected_terms": ["saved filters"],
"preserve_numbers": true
}
}
The score gate is disabled by default, so obvious filler can be edited even when the style score is low. Set rewrite_gate.enabled to true to require its score and length thresholds. Short-text scores are less informative. A tight change budget and a demanding reading target may conflict. If the candidate can't meet both, the API returns the original. It never silently loosens your limits.
Check a revision you already have
POST /v1/verify. This example uses code only. Changing 12 to 13 should fail the number-preservation check even though the edit is small.
{
"original": "We shipped 12 fixes on Friday.",
"revised": "We shipped 13 fixes on Friday.",
"allow_ai": false,
"constraints": { "max_change_ratio": 0.35, "preserve_numbers": true }
}
Save explicit writing preferences
POST /v1/profiles. The returned id can be supplied as profile_id on later analysis or rewrite requests.
{
"name": "Plain project updates",
"genre": "technical",
"instructions": "Use direct language. Preserve qualifications and technical terms.",
"rules": [{
"id": "prefer.use",
"type": "prefer",
"phrase": "utilize",
"replacement": "use",
"description": "Prefer the simpler word when it fits.",
"auto_fix": false
}],
"samples": [],
"defaults": { "max_change_ratio": 0.35 }
}
Profiles are saved in your workspace. To replace or delete one, send its current revision in the X-Profile-Revision header. Request rules override profile rules with the same ID, and request constraints override profile defaults.
Put instructions in instructions and approved prose in samples. Profile import proposes rules for review; it does not save them automatically. Profile defaults hold constraints only. Supply gate settings, micro limits, model level, and review preferences on each request.
Read the response before using the text
Analysis fields below are at the top level of /v1/analyze. A rewrite includes them under before and after, unless return_analysis: false. The individual /score, /quality, and /explain endpoints return their selected object directly.
| Field | Meaning |
|---|---|
score.style_score | Pattern density from 0 to 100. Lower means fewer matched style patterns. It is not an authorship probability. |
quality | Mechanics, reading level, rhythm, and descriptive voice-sample comparisons. Some results are null or insufficient when the sample is too small. |
explain.findings | Locations, rule IDs, matched text, and explanations. New rhythm and repetition suggestions have scored: false. |
accepted | Whether the candidate passed hard constraints and any performed meaning review. Read status first: skipped or unchanged text can still have accepted: true. This does not mean an edit or review occurred. |
text | The accepted revision, or the original when a candidate was rejected. An accepted result may be unchanged. |
validation.checks | Each requested mechanical check is passed, failed, or unverified. Failed or unverified hard checks reject a rewrite. |
original_score / rewrite_gate | The original score and the decision to permit AI editing, always included even with return_analysis: false. passed is true when the configured size and score requirements pass, or when you explicitly disable the gate. Reasons are insufficient_text, below_style_threshold, style_threshold_met, or disabled. The same gate appears under rewrite_gate in /score responses. |
attempts | One record per patch-generation call, with original offsets, acceptance, and rejection reasons. Invalid patches are discarded; optional retries share the call budget. |
document_editing | Generation/review counts, completion reason, and accepted character edits. Document mode covers the complete draft with no four-edit cap. |
micro_editing | Call counts, limits, coverage, completion reason, and accepted patches with original offsets. spans_remaining counts unreviewed spans. A partially_rewritten result contains accepted edits with incomplete coverage; unchanged output can also have incomplete coverage. |
finding_changes | Raw before/after counts per rule in the returned text. A lower density score alone can result from added filler. |
usage | On rewrite responses, total input and output tokens from the rewrite and review calls made in that request. |
Rewrite statuses: skipped means the score gate failed; unchanged means no change was returned; partially_rewritten means accepted changes with unreviewed spans; rewritten means the complete candidate passed validation and meaning review in document mode, or all planned spans were reviewed in micro mode; constraints_unsatisfied means final validation or meaning review rejected the candidate. Per-call acceptance in attempts does not override the final accepted value. A completed scan does not prove every possible improvement was found.
HTTP 200 can include accepted: false and status: "constraints_unsatisfied". That means the service ran successfully and rejected the edit. Rejected candidate differences remain in validation.comparison for diagnosis; do not automatically apply them.
On /v1/verify, constraints_satisfied covers mechanical checks only. If you enable AI review there with allow_ai: true and semantic_review: true, read the separate semantic result too.
Controls and units
The table lists top-level rewrite fields. Document mode is the default. Set mode: "micro" for the legacy phrase editor. Gate and micro settings use their own nested objects; edit budgets, reading targets, output limits, and preservation flags belong inside constraints. Unknown fields are rejected. Omitted object fields keep their defaults.
| Field | Behavior |
|---|---|
allow_ai | Defaults true only on /rewrite; explicitly send true for AI proofreading, profile import, or review. Most other text endpoints default false. |
instructions, tone, audience | Rewrite guidance: up to 6,000, 200, and 200 UTF-16 units respectively. Guidance does not override hard constraints or structured gate settings. |
profile_id, rules, writing_samples | A saved workspace profile, up to 100 literal/contextual rules, and up to four approved prose samples. Same-ID request rules override profile rules. |
locale, format, genre | English dialect defaults to en-US; also GB, CA, AU. Format is plain (default) or markdown. Genre is optional: general, technical, business, personal, educational, or creative. |
semantic_review | Document edits always receive a meaning review, even if this flag is false. The flag controls optional review in micro mode and defaults true on rewriting. |
retry_on_failure | Defaults true. Document mode permits one correction cycle after mechanical or meaning-review failure, for at most two edits and two reviews. Micro mode retries invalid patches within its generation budget. Provider errors are not automatically retried. |
return_edits, return_analysis | Both default true. False omits the top-level character diff or before/after analysis respectively. Original score, gate, validation, attempts, and micro_editing.patches still return. |
/proofread defaults to reporting findings. apply:true applies conservative deterministic corrections. Adding allow_ai:true uses the score gate and AI micro-editing, with the default micro limits. It does not accept rewrite-only fields such as micro, instructions; use /rewrite for those controls. /review and optional meaning review in /verify use AI services selected by Unslop. Neither is blocked by the rewrite gate.
constraints.max_change_ratiocharges added plus removed prose tokens against the original. The document rewrite default is 1.5; micro mode defaults to 0.15, unless overridden by your profile or request. A word replacement charges both sides; whitespace does not count toward this ratio.rewrite_gateworks on/score,/analyze,/rewrite, and AI/proofread. Fields:enabled(boolean, default true),threshold(0–100, default 20), andminimum_words(integer 0–20,000, default 50). Omitted fields keep their defaults. Zero words disables the size requirement; zero score permits any scorable prose. Text with no scorable prose still fails an enabled gate. The response echoes the settings and reason. Request settings do not change other requests.- In
mode: "micro"only,micro.max_calls: 1–12, default 4. Meaning review adds at most one call. Remaining account allowance can reduce the generation budget.micro.max_span_words: 1–24, default 8;micro.max_span_chars: 1–160 Unicode code points, default 60. Both sides of each replacement, and adjacent patches separated only by whitespace, must fit these limits. These are size limits, not watermark guarantees. constraints.max_edit_countlimits contiguous character-diff regions.constraints.max_edit_sizelimits the larger side of each region in Unicode code points. A replacement can produce several regions.- Each source or revision text field allows up to 20,000 UTF-16 units. The total JSON body limit is 256 KB.
constraints.max_output_wordsandconstraints.max_output_charscap the full output, including code and markup. The character cap uses Unicode code points.- Finding and protected-span offsets use half-open UTF-16 ranges:
startis included,endis excluded. This matches JavaScript string slicing. An emoji such as 😀 uses two UTF-16 units but one Unicode code point. Don't split its pair. - Choose only one of
target_age,readability_target, orreadability_ceiling. An explicit choice replaces the profile's age/grade/ceiling default. Exact targets use a tolerance, default 1 grade. Ceilings do not add tolerance. target_ageaccepts whole ages 6 through 18 and approximates grade as age minus 5. Reading grades need at least 30 words and two sentences. See the limits of readability formulas.writing_complexity_targetacceptssimplebelow grade 8,moderatefrom 8 to below 13, orcomplexat 13 and above. This describes the text rather than the author's ability.- Numbers and quotations are protected by default. Markdown formatting protection is also on by default when
format: "markdown". Micro-edits preserve paragraph breaks even if that protection is disabled. Thepreserve_paragraph_breaksoption remains useful when verifying an independently edited revision. writing_samplesaccepts up to four prose samples per request, up to 5,000 UTF-16 units each. Descriptive comparisons require two samples totaling at least 20 sentences; they are not hard voice constraints.
These request settings complement micro, constraints, rules, writing_samples, instructions, tone, audience, semantic_review, retry_on_failure, and response-detail flags. Account quotas, maximum request size, available features, and server-enforced upper bounds remain service limits. The exact fields and ranges are in OpenAPI. GET /v1/capabilities reports available features and limits. Model identities and provider selection are not exposed by the API.
Troubleshooting
| Outcome | What to check |
|---|---|
| 400 | The JSON body could not be parsed. |
| 401 | Supply a valid workspace key in the Bearer header. Reading a public page doesn't grant API access. |
| 403 | Check origin and session access. Account cookies require the same origin; cross-origin applications need a bearer key and an allowed origin. |
| 404 | Check the endpoint or profile ID. Profiles are private to their workspace. |
| 413 | The body is too large. Requests are limited to 256 KB; individual text fields also have schema limits. |
| 415 | Send Content-Type: application/json. |
| 422 | Read error.details when present. Unknown fields, conflicting targets, invalid spans, or missing AI consent can cause rejection. |
| 409 or 428 on a profile | Read the current profile revision and include it in X-Profile-Revision. Another edit may have changed the revision. |
| 429 | Read the error code. Minute limits reset at the next UTC minute; daily word/model limits reset at midnight UTC. Avoid immediate retry loops. |
| 500 | An unexpected server error occurred. Keep the request ID for the owner; do not include keys or private text in a report. |
| 502 or 503 | A provider or required service failed or is unavailable. The owner needs to check model credentials, access, and billing. An unchecked rewrite isn't accepted. |
| Original text returned | Inspect status and rewrite_gate first, then accepted, checks, and any meaning review. A gate skip is not a provider error. Only loosen a constraint when you intend to permit more change. |
| No rhythm warning | Warnings need enough prose: 10 sentences or 5 paragraphs. Structured Markdown blocks can be excluded. The absence of a warning isn't proof of quality. |
When reporting a problem, keep the request_id or X-Request-Id value. Don't include your key. Share submitted text only if you intend the recipient to see it.
Run history
GET /v1/history reports workspace writing-run totals by level and the latest 100 score, analyze, rewrite and proofread results. Rows contain timestamps, levels, outcomes, before/after style scores and settled charges, without document text. Counts start when history is enabled; older runs are not backfilled. Billing replays count once. A null charge means no prepaid charge was reported. This history is separate from billing records and is removed when the account is deleted.
Data, consent, and usage
Deterministic analysis runs on the server without a model call. Rewriting and meaning review send the relevant text and guidance to external AI services selected by Unslop. Saved profiles persist in workspace storage; prepaid requests may briefly cache response text for retries. See billing and retention. See where your text goes.
Public prepaid accounts allow 20 requests per minute, 500 requests per day, 100,000 submitted words per day and 100 model calls per day. When billing is disabled, the trial allowance is 10,000 words and 5 calls per day. Individual keys can have different limits. GET /v1/usage reports yours. All submitted string values, including samples, instructions, and rule text, count toward words; failed provider attempts count toward calls.
External detector or watermark requests require allow_external: true and an approved, configured provider. Reading the static reference pages makes no API or model calls. A score-gate skip uses no AI calls but still counts toward request and word allowances. micro_editing reports generation and review call counts; semantic_review reports meaning-review findings. Document editing always checks meaning and can make one correction attempt. Each generation or review counts toward the account allowance. Micro mode has separate phrase-edit limits.